主题
默认情况下,AgentWorkflow 在多次运行之间是无状态的,也就是说 agent 不会记得之前的运行。
要维护状态,就得保存先前的状态。在 LlamaIndex 里,Workflows 提供了一个 Context 类,可以在单次运行内部以及多次运行之间维护状态。由于 AgentWorkflow 本身就是一个预置的 Workflow,我们现在也能直接用它。
from llama_index.core.workflow import Context为了在运行之间保持状态,我们新建一个名为 ctx 的 Context。把 workflow 传进去,以便为这个 Context 对象做好与该工作流的配套配置。
ctx = Context(workflow)有了配置好的 Context,就可以把它传给第一次运行。
response = await workflow.run(user_msg="Hi, my name is Laurie!", ctx=ctx)
print(response)得到的结果是:
Hello Laurie! How can I assist you today?现在我们再运行一次这个工作流、追问一个问题,它就记得刚才的信息了:
response2 = await workflow.run(user_msg="What's my name?", ctx=ctx)
print(response2)得到的结果是:
Your name is Laurie!在更长的时间尺度上维护状态
Context 是可序列化的,因此可以存进数据库、文件等地方,之后再加载回来。
JsonSerializer 是一个简单的序列化器,用 json.dumps 和 json.loads 完成上下文的序列化与反序列化。
JsonPickleSerializer 则使用 pickle 完成上下文的序列化与反序列化。如果你的上下文里含有无法序列化的对象,就可以用这个序列化器。
和其他导入一样,先把序列化器引入:
from llama_index.core.workflow import JsonPickleSerializer, JsonSerializer随后就能把上下文序列化成字典并存进文件:
ctx_dict = ctx.to_dict(serializer=JsonSerializer())再把它反序列化回 Context 对象,就能像之前一样继续提问:
restored_ctx = Context.from_dict(
workflow, ctx_dict, serializer=JsonSerializer()
)
response3 = await workflow.run(user_msg="What's my name?", ctx=restored_ctx)你可以在这里看到这个示例的完整代码。
工具与状态
工具也可以定义为能够访问工作流上下文的形式。这意味着你可以在上下文里读写变量并在工具中使用它们,也可以用它们在工具之间传递信息。
AgentWorkflow 使用一个名为 state 的上下文变量,每个 agent 都能访问它。你可以放心依赖 state 中的信息,而不必显式传入。
要访问 Context,Context 参数必须放在工具函数的第一个参数位置——下面的工具只是往 state 里添加一个名字,正是这样做的:
async def set_name(ctx: Context, name: str) -> str:
async with ctx.store.edit_state() as ctx_state:
ctx_state["state"]["name"] = name
return f"Name set to {name}"现在我们可以创建使用这个工具的 agent。你可以选择性地提供 agent 的初始状态,这里我们就这么做:
workflow = AgentWorkflow.from_tools_or_functions(
[set_name],
llm=llm,
system_prompt="You are a helpful assistant that can set a name.",
initial_state={"name": "unset"},
)接着创建一个 Context,并向 agent 询问状态里的信息:
ctx = Context(workflow)
# check if it knows a name before setting it
response = await workflow.run(user_msg="What's my name?", ctx=ctx)
print(str(response))得到的结果是:
Your name has been set to "unset."然后在新的一次运行里显式设置这个名字:
response2 = await workflow.run(user_msg="My name is Laurie", ctx=ctx)
print(str(response2))Your name has been updated to "Laurie."之后我们可以再问 agent 这个名字,也可以直接读取 state 里的值:
state = await ctx.store.get("state")
print("Name as stored in state: ", state["name"])得到的结果是:
Name as stored in state: Laurie你可以在这里看到这个示例的完整代码。
下一节我们来了解流式输出与事件。