llama_index [Bug]:无法使用ChromaDB进行矢量内存操作

s8vozzvw  于 23天前  发布在  其他
关注(0)|答案(1)|浏览(13)

错误描述

尝试将chromadb用作矢量内存时,我在sub_dicts上收到了一个键错误。我不确定这是否是chromadb的问题,因为我在将vector_store设置为None并使用内存矢量存储时没有出现错误。

版本

0.10.68

重现步骤

假设您已经有一个名为messages的chromaDB示例

import chromadb
from llama_index.vector_stores import ChromaVectorStore
from llama_index.core.memory import VectorMemory, Simple ComposableMemory
from llama_index.core.agent import FunctionCallingAgentWorker
from llama_index.core.tools import FunctionTool

client = chromadb.PersistentClient(path= <path to db>)
collection = client.get_or_create_collection("memory")
vector_store = ChromaVectorStore(chroma_collection = collection)
vector_memory = VectorMemory.from_defaults(
    vector_store = vector_store,
    embed_model = embed_model,
    retriever_kwargs = {"similarity_top_k": 2}
)
chat_memory_buffer = ChatMemoryBuffer.from_defaults()
composable_memory = SimpleComposableMemory.from_defaults(
    primary_memory = chat_memory_buffer,
    secondary_memory_sources=[vector_memory]
)
def add(a, b):
    """Adds 2 values given - these can be integers, floats or
    string concatenation"""
    return a + b

tools = [FunctionTool.from_defaults(add)]

agent_worker = FunctionCallingAgentWorker.from_tools(
    tools = tools,
    llm = llm,
    verbose = True
)
agent = agent_worker.as_agent(memory=composable_memory)
response = agent.chat(<Question from memory>)

相关日志/回溯

File /app/tlim2/anaconda3/envs/llamaindex/lib/python3.12/site-packages/llama_index/core/instrumentation/dispatcher.py:260, in Dispatcher.span.<locals>.wrapper(func, instance, args, kwargs)
    252 self.span_enter(
    253     id_=id_,
    254     bound_args=bound_args,
   (...)
    257     tags=tags,
    258 )
    259 try:
--> 260     result = func(*args, **kwargs)
    261 except BaseException as e:
    262     self.event(SpanDropEvent(span_id=id_, err_str=str(e)))

File /app/tlim2/anaconda3/envs/llamaindex/lib/python3.12/site-packages/llama_index/core/callbacks/utils.py:41, in trace_method.<locals>.decorator.<locals>.wrapper(self, *args, **kwargs)
     39 callback_manager = cast(CallbackManager, callback_manager)
     40 with callback_manager.as_trace(trace_id):
---> 41     return func(self, *args, **kwargs)

File /app/tlim2/anaconda3/envs/llamaindex/lib/python3.12/site-packages/llama_index/core/agent/runner/base.py:646, in AgentRunner.chat(self, message, chat_history, tool_choice)
    641     tool_choice = self.default_tool_choice
    642 with self.callback_manager.event(
    643     CBEventType.AGENT_STEP,
    644     payload={EventPayload.MESSAGES: [message]},
    645 ) as e:
--> 646     chat_response = self._chat(
    647         message=message,
    648         chat_history=chat_history,
    649         tool_choice=tool_choice,
    650         mode=ChatResponseMode.WAIT,
    651     )
    652     assert isinstance(chat_response, AgentChatResponse)
    653     e.on_end(payload={EventPayload.RESPONSE: chat_response})

File /app/tlim2/anaconda3/envs/llamaindex/lib/python3.12/site-packages/llama_index/core/instrumentation/dispatcher.py:260, in Dispatcher.span.<locals>.wrapper(func, instance, args, kwargs)
    252 self.span_enter(
    253     id_=id_,
    254     bound_args=bound_args,
   (...)
    257     tags=tags,
    258 )
    259 try:
--> 260     result = func(*args, **kwargs)
    261 except BaseException as e:
    262     self.event(SpanDropEvent(span_id=id_, err_str=str(e)))

File /app/tlim2/anaconda3/envs/llamaindex/lib/python3.12/site-packages/llama_index/core/agent/runner/base.py:578, in AgentRunner._chat(self, message, chat_history, tool_choice, mode)
    575 dispatcher.event(AgentChatWithStepStartEvent(user_msg=message))
    576 while True:
    577     # pass step queue in as argument, assume step executor is stateless
--> 578     cur_step_output = self._run_step(
    579         task.task_id, mode=mode, tool_choice=tool_choice
    580     )
    582     if cur_step_output.is_last:
    583         result_output = cur_step_output

File /app/tlim2/anaconda3/envs/llamaindex/lib/python3.12/site-packages/llama_index/core/instrumentation/dispatcher.py:260, in Dispatcher.span.<locals>.wrapper(func, instance, args, kwargs)
    252 self.span_enter(
    253     id_=id_,
    254     bound_args=bound_args,
   (...)
    257     tags=tags,
    258 )
    259 try:
--> 260     result = func(*args, **kwargs)
    261 except BaseException as e:
    262     self.event(SpanDropEvent(span_id=id_, err_str=str(e)))

File /app/tlim2/anaconda3/envs/llamaindex/lib/python3.12/site-packages/llama_index/core/agent/runner/base.py:412, in AgentRunner._run_step(self, task_id, step, input, mode, **kwargs)
    408 # TODO: figure out if you can dynamically swap in different step executors
    409 # not clear when you would do that by theoretically possible
    411 if mode == ChatResponseMode.WAIT:
--> 412     cur_step_output = self.agent_worker.run_step(step, task, **kwargs)
    413 elif mode == ChatResponseMode.STREAM:
    414     cur_step_output = self.agent_worker.stream_step(step, task, **kwargs)

File /app/tlim2/anaconda3/envs/llamaindex/lib/python3.12/site-packages/llama_index/core/instrumentation/dispatcher.py:260, in Dispatcher.span.<locals>.wrapper(func, instance, args, kwargs)
    252 self.span_enter(
    253     id_=id_,
    254     bound_args=bound_args,
   (...)
    257     tags=tags,
    258 )
    259 try:
--> 260     result = func(*args, **kwargs)
    261 except BaseException as e:
    262     self.event(SpanDropEvent(span_id=id_, err_str=str(e)))

File /app/tlim2/anaconda3/envs/llamaindex/lib/python3.12/site-packages/llama_index/core/callbacks/utils.py:41, in trace_method.<locals>.decorator.<locals>.wrapper(self, *args, **kwargs)
     39 callback_manager = cast(CallbackManager, callback_manager)
     40 with callback_manager.as_trace(trace_id):
---> 41     return func(self, *args, **kwargs)

File /app/tlim2/anaconda3/envs/llamaindex/lib/python3.12/site-packages/llama_index/core/agent/function_calling/step.py:305, in FunctionCallingAgentWorker.run_step(self, step, task, **kwargs)
    299 tools = self.get_tools(task.input)
    301 # get response and tool call (if exists)
    302 response = self._llm.chat_with_tools(
    303     tools=tools,
    304     user_msg=None,
--> 305     chat_history=self.get_all_messages(task),
    306     verbose=self._verbose,
    307     allow_parallel_tool_calls=self.allow_parallel_tool_calls,
    308 )
    309 tool_calls = self._llm.get_tool_calls_from_response(
    310     response, error_on_no_tool_call=False
    311 )
    312 tool_outputs: List[ToolOutput] = []

File /app/tlim2/anaconda3/envs/llamaindex/lib/python3.12/site-packages/llama_index/core/agent/function_calling/step.py:195, in FunctionCallingAgentWorker.get_all_messages(self, task)
    192 def get_all_messages(self, task: Task) -> List[ChatMessage]:
    193     return (
    194         self.prefix_messages
--> 195         + task.memory.get(input=task.input)
    196         + task.extra_state["new_memory"].get_all()
    197     )

File /app/tlim2/anaconda3/envs/llamaindex/lib/python3.12/site-packages/llama_index/core/memory/simple_composable_memory.py:76, in SimpleComposableMemory.get(self, input, **kwargs)
     74 def get(self, input: Optional[str] = None, **kwargs: Any) -> List[ChatMessage]:
     75     """Get chat history."""
---> 76     return self._compose_message_histories(input, **kwargs)

File /app/tlim2/anaconda3/envs/llamaindex/lib/python3.12/site-packages/llama_index/core/memory/simple_composable_memory.py:89, in SimpleComposableMemory._compose_message_histories(self, input, **kwargs)
     87 secondary_histories = []
     88 for mem in self.secondary_memory_sources:
---> 89     secondary_history = mem.get(input, **kwargs)
     90     secondary_history = [m for m in secondary_history if m not in messages]
     92     if len(secondary_history) > 0:

File /app/tlim2/anaconda3/envs/llamaindex/lib/python3.12/site-packages/llama_index/core/memory/vector_memory.py:140, in VectorMemory.get(self, input, initial_token_count, **kwargs)
    134 nodes = retriever.retrieve(input or "")
    136 # retrieve underlying messages
    137 return [
    138     ChatMessage.parse_obj(sub_dict)
    139     for node in nodes
--> 140     for sub_dict in node.metadata["sub_dicts"]
    141 ]

KeyError: 'sub_dicts'
qc6wkl3g

qc6wkl3g1#

你遇到的错误, KeyError: 'sub_dicts' ,表示 node 对象中的 metadata 属性不包含预期的 sub_dicts 键。当使用 ChromaVectorStoreVectorMemory 时会出现这个问题。

可能的解决方案

要解决此问题,请确保 node 对象中的 metadata 属性已正确填充 sub_dicts 键。你可以修改创建 TextNode 示例的代码,将 sub_dicts 键添加到 metadata 字典中。
以下是如何修改 TextNode 创建以包含 sub_dicts 键的示例:

from llama_index.core.schema import TextNode

nodes = [
    TextNode(
        text="The Shawshank Redemption",
        metadata={
            "author": "Stephen King",
            "theme": "Friendship",
            "year": 1994,
            "sub_dicts": []  # Add this line
        },
    ),
    TextNode(
        text="The Godfather",
        metadata={
            "director": "Francis Ford Coppola",
            "theme": "Mafia",
            "year": 1972,
            "sub_dicts": []  # Add this line
        },
    ),
    # Add similar lines for other TextNode instances
]

解释

node 对象中的 metadata 属性是一个可以包含各种键值对的字典。在你的情况中,似乎预期的 sub_dicts 键不存在。通过添加具有适当值(例如,空列表)的 sub_dicts 键,可以避免 KeyError

其他上下文

如果你需要更多关于如何填充和处理 metadata 属性的信息,可以参考 ChromaVectorStore 类中相关的方法,例如处理 metadata 属性之前存储它的 add 方法。
通过确保 metadata 属性包含 sub_dicts 键,你应该能够解决 KeyError 并成功使用 ChromaVectorStoreVectorMemory

  • 要继续与 Dosu 交谈,请提及 @dosu。*

相关问题