Ash ai error when generating embddding

When trying to use Ash AI to generate a embedding, I got the error: * (Oban.CrashError) (throw) {DBConnection, #Reference<0.1746484685.788004865.129140>, #Ash.Changeset<domain: Qst.Templates, action_type: :update, action: :ash_ai_update_embeddings, attributes: %{full_text_vector: Ash.Vector.new([0.007031387183815241, -0.009794930927455425, ...]), updated_at: ~U[2025-06-21 06:34:27.031518Z]}, relationships: %{}, errors: [%Ash.Error.Unknown.UnknownError{error: "** (FunctionClauseError) no function clause matching in Pgvector.new/1", field: nil, value: nil, splode: Ash.Error, bread_crumbs: [], vars: [], path: [], stacktrace: #splode.Stacktrace<>, class: :unknown}], data: %Qst.Templates.QuestTemplate{id: "97eee691-64df-47e0-900a-9e8eaff83a25", name: "Dragon Slayer", description: "Epic dragon quest", inserted_at: ~U[2025-06-21 06:34:26.256243Z], updated_at: ~U[2025-06-21 06:34:26.256243Z], creator_id: "0a622c8d-6d03-4ca6-bef9-84795f3d8d7d", full_text_vector: #Ash.NotLoaded<:attribute, field: :full_text_vector>, task_templates: #Ash.NotLoaded<:relationship, field: :task_templates>, creator: #Ash.NotLoaded<:relationship, field: :creator>, meta: #Ecto.Schema.Metadata<:loaded, "quest_templates">}, context: %{changed?: true}, valid?: false>} It seems the embedding is returned correctly but can't convert to Pgvector. Does anyone has similar issue? Thanks a lot.
14 Replies
ZachDaniel
ZachDaniel4mo ago
What does your embedding model look like?
blade
bladeOP4mo ago
defmodule Qst.Ai.GeminiEmbeddingModel do use AshAi.EmbeddingModel @dimensions 768 @endpoint "https://generativelanguage.googleapis.com/v1beta/models/embedding-001:embedContent" @impl true def dimensions(_opts), do: @dimensions @impl true def generate(texts, _opts) when is_list(texts) do api_key = System.fetch_env!("GEMINI_API_KEY") body = %{"content" => %{"parts" => [%{"text" => Enum.join(texts, "\n\n")}]}} case Req.post(@endpoint <> "?key=" <> api_key, json: body) do {:ok, %Req.Response{status: 200, body: %{"embedding" => %{"values" => values}}}} -> {:ok, [values]} {:ok, %Req.Response{status: status, body: body}} -> {:error, {status, body}} {:error, error} -> {:error, error} end end end vectorize do full_text do text(fn r -> "#{r.name} #{r.description}" end) used_attributes([:name, :description]) end strategy :after_action embedding_model GeminiEmbeddingModel end And above is the vectorize part. I use the strategy :after_action when testing.
ZachDaniel
ZachDaniel4mo ago
You want to return one vector embedding per input So I think maybe you are doing [values] But you just want values
blade
bladeOP4mo ago
The values is indeed a list of float. However, if I only return values, I will get the following error: Unknown Error * ** (FunctionClauseError) no function clause matching in Ash.Vector.new/1 (ash 3.5.23) lib/ash/vector.ex:19: Ash.Vector.new(0.007031387) (ash 3.5.23) lib/ash/type/vector.ex:37: Ash.Type.Vector.cast_input/2 (ash 3.5.23) lib/ash/type/type.ex:1025: Ash.Type.cast_input/3 (ash 3.5.23) lib/ash/changeset/changeset.ex:6214: Ash.Changeset.do_change_attribute/4 (elixir 1.18.4) lib/enum.ex:2546: Enum."-reduce/3-lists^foldl/2-0-"/3 (ash 3.5.23) lib/ash/changeset/changeset.ex:3256: Ash.Changeset.run_change_or_validation/6 (ash 3.5.23) lib/ash/changeset/changeset.ex:3109: anonymous fn/6 in Ash.Changeset.run_action_changes/6 (elixir 1.18.4) lib/enum.ex:2546: Enum."-reduce/3-lists^foldl/2-0-"/3 (ash 3.5.23) lib/ash/changeset/changeset.ex:3105: Ash.Changeset.run_action_changes/6 (ash 3.5.23) lib/ash/changeset/changeset.ex:2544: Ash.Changeset.do_for_action/4 (qst 0.1.0) deps/ash_oban/lib/transformers/define_schedulers.ex:1027: Qst.Templates.QuestTemplate.AshOban.Worker.ReindexEmbedding.perform/1 (oban 2.19.4) lib/oban/queue/executor.ex:145: Oban.Queue.Executor.perform/1 (oban 2.19.4) lib/oban/queue/executor.ex:77: Oban.Queue.Executor.call/1 (oban 2.19.4) lib/oban/engines/inline.ex:97: Oban.Engines.Inline.execute_job/2 (oban 2.19.4) lib/oban/engines/inline.ex:37: Oban.Engines.Inline.insert_job/3 (oban 2.19.4) lib/oban/engine.ex:210: anonymous fn/4 in Oban.Engine.insert_job/3 (oban 2.19.4) lib/oban/engine.ex:387: anonymous fn/3 in Oban.Engine.with_span/4
ZachDaniel
ZachDaniel4mo ago
Ah, okay, so I don't know how Gemini works But it looks like you're joining the texts into one string You need to return a list of one vector per string in the input list
blade
bladeOP4mo ago
#Ash.Changeset< domain: Qst.Templates, action_type: :update, action: :ash_ai_update_embeddings, attributes: %{ vectorized_name: Ash.Vector.new([-0.09240056574344635, 0.006294603459537029, -0.012871873565018177]), vectorized_description: Ash.Vector.new([-0.08480250090360641, 0.10270774364471436, -0.027802953496575356]), full_text_vector: Ash.Vector.new([-0.0896868035197258, 0.012641902081668377, -8.565243915654719e-4]) }, relationships: %{}, errors: [], data: %Qst.Templates.QuestTemplate{ id: "29a256f5-97b7-4566-abc4-21346436a362", name: "Dragon Slayer", description: "Epic dragon quest", inserted_at: ~U[2025-06-21 19:58:21.762675Z], updated_at: ~U[2025-06-21 19:58:21.762675Z], creator_id: "f1e2e966-1faf-4776-a90e-c36d3ca65295", vectorized_name: #Ash.NotLoaded<:attribute, field: :vectorized_name>, vectorized_description: #Ash.NotLoaded<:attribute, field: :vectorized_description>, full_text_vector: #Ash.NotLoaded<:attribute, field: :full_text_vector>, task_templates: #Ash.NotLoaded<:relationship, field: :task_templates>, creator: #Ash.NotLoaded<:relationship, field: :creator>, meta: #Ecto.Schema.Metadata<:loaded, "quest_templates"> }, valid?: true > Here is the changeset I printed for debug. I remove some floats as it's too long. I do not join the text but generated vector for each text now for (vectorized_name / vectorized_description and full_text_vector) The error is still: %Ash.Error.Unknown.UnknownError{error: "** (FunctionClauseError) no function clause matching in Pgvector.new/1", field: nil, value: nil, splode: Ash.Error, bread_crumbs: [], vars: [], path: [], stacktrace: #splode.Stacktrace<>, class: :unknown}], data: %Qst.Templates.QuestTemplate{id: "29a256f5-97b7-4566-abc4-21346436a362", name: "Dragon Slayer", description: "Epic dragon quest", inserted_at: ~U[2025-06-21 19:58:21.762675Z
ZachDaniel
ZachDaniel4mo ago
Can I see the latest version of your model? Use triple backticks to make code easier to read
blade
bladeOP4mo ago
defmodule Qst.Templates.QuestTemplate do use Ash.Resource, otp_app: :qst, domain: Qst.Templates, data_layer: AshPostgres.DataLayer, extensions: [AshAi, AshOban] require Ash.Query postgres do table "quest_templates" repo Qst.Repo end vectorize do full_text do text(fn r -> """ Name: #{r.name} Description: #{r.description} """ end) used_attributes([:name, :description]) end strategy :after_action attributes(name: :vectorized_name, description: :vectorized_description) embedding_model(GeminiEmbeddingModel) end actions do defaults [:create, :read, :update, :destroy] default_accept [:name, :description, :creator_id] read :search do argument :query, :string, allow_nil?: false prepare before_action(fn query, context -> case GeminiEmbeddingModel.generate([query.arguments.query], []) do {:ok, search_vector} -> IO.inspect(search_vector, label: "search_vector") query |> Ash.Query.filter( not is_nil(full_text_vector) and vector_cosine_distance(full_text_vector, ^search_vector) < 0.5 ) |> Ash.Query.sort( {calc(expr(vector_cosine_distance(full_text_vector, ^search_vector)), type: :float ), :asc} ) |> Ash.Query.limit(10) {:error, error} -> {:error, error} end end) end end attributes do uuid_primary_key :id attribute :name, :string, allow_nil?: false attribute :description, :string timestamps() end end Here it is. Really appreciate your time. Thanks.
ZachDaniel
ZachDaniel4mo ago
Sorry, I mean, your EmbeddingModel
blade
bladeOP4mo ago
defmodule Qst.Ai.GeminiEmbeddingModel do use AshAi.EmbeddingModel @dimensions 768 @endpoint "https://generativelanguage.googleapis.com/v1beta/models/text-embedding-004:embedContent" @impl true def dimensions(_opts), do: @dimensions @impl true def generate(texts, _opts) when is_list(texts) do {:ok, Enum.map(texts, fn text -> {:ok, values} = generate_one(text, _opts) values end)} end def generate_one(text, _opts) do api_key = System.fetch_env!("GEMINI_API_KEY") body = %{"content" => %{"parts" => %{"text" => text}}, "taskType" => "SEMANTIC_SIMILARITY"} case Req.post(@endpoint <> "?key=" <> api_key, json: body) do {:ok, %Req.Response{status: 200, body: %{"embedding" => %{"values" => values}} = response_body}} -> {:ok, values} {:ok, %Req.Response{status: status, body: body}} -> {:error, {status, body}} {:error, error} -> {:error, error} end end end This is the EmbeddingModel. Thanks.
ZachDaniel
ZachDaniel4mo ago
Can you drop an IO.inspect at the end to show the return value? I'm confident something is wrong with that module ultimately.
blade
bladeOP4mo ago
generate result: {:ok, [ [-0.092400566, 0.0062946035, -0.10562682, 0.056037433, 0.09453738, 0.025487343, 0.01596396, -0.017847484, 0.047371704, 0.046806518, 0.0326265, -0.027291933, -0.025053283, 0.0058116233, -0.025200406, 0.026335014, -0.05078257, 0.020042488, -0.08787288, 0.040349603, -0.022270834, ...], [-0.0848025, -0.008653622, -0.07089128, 0.022988718, 0.071521655, 0.042495444, 0.011308266, -0.033617016, 0.039227992, -0.0023086653, 0.00406599, -0.023387631, 0.0057275696, -0.02201007, -0.052452102, 0.028986359, -0.061633606, -0.010335462, -0.057401214, -0.009707467, ...], [-0.0896868, 0.012641902, -0.06116206, 0.033900578, 0.064447895, 0.044433285, 0.011002703, -0.026450213, 0.036916945, 0.052138157, 0.025357082, -0.040204428, -0.0046259044, -0.0029942, -0.021914972, -0.017778914, -0.04252304, -0.0077015706, -0.013262843, -0.051168382, 0.010696245, -0.06892958, -0.011229938, -0.07094381, ...] ]} Here is the result. I am not sure what's the expected returns here.
ZachDaniel
ZachDaniel4mo ago
Huh. That looks right to be honestly. Is this repo something you can share? Could you maybe put a repro together for me?
blade
bladeOP4mo ago
Will work on the repo. For now, I think the main issue is when call Pgvector.new, the Ash.Vector.new([...]) was passed. I don't know why it happens. Maybe I miss some config for type convert? Finally, I found the root cause. It's my bad, I am using Pgvector.Extensions.Vector instead of AshPostgres.Extensions.Vector for postgres types. Thanks so much for your time.

Did you find this page helpful?