一个循环就够了:构建对话AI代理

在构建AI代理几个月后,我得出一个反直觉的结论:那些大家都在使用的花哨代理框架?你可能并不需要它们。
让我解释一下我是如何得出这个结论的。
本质复杂性不在技术层面
几个月前,我加入了一家AI初创公司担任创始工程师。
来自多年数据科学工作的背景,我以为我知道自己要面对什么。我曾经使用过LangChain、CrewAI、AutoGen、Pydantic AI等库,并在AI工程训练营中教授这些代理框架。我有满满的多代理系统、思维链提示实验和RAG管道的笔记本。
相反,我发现自己正在阅读Diana Deibel和Rebecca Evanhoe在2021年出版的《与事物对话:聊天和语音的UX设计》,这本书远在ChatGPT和现代AI浪潮之前。
这本书让我看到了我一直忽略的东西:构建对话AI代理主要不是技术挑战。它是对话设计挑战。而对话是混乱的、文化的、深深人性化的。
轮换发言很困难
首先让我震惊的是,我们开发者在教授系统最基本的人类技能方面是多么糟糕:知道何时让AI说话,何时等待。
在AI中有一个叫做"轮换发言"的概念——谁在什么时候说话的无形舞蹈。人类是这方面的大师。我们捕捉微小的线索:轻微的吸气、姿势的变化、某人声音在思考结束时下降的方式。我们本能地知道什么时候轮到我们。
但当你构建代理时,你必须明确地编程这些决策:用户是否完成了他们的想法?系统应该现在回应还是等待更多输入?
消息传递问题
现代消息系统引入了自己奇怪的动态。你知道那个打字指示器——"Adilet正在输入..."吗?那个小小的社会契约说"等一下,我还没说完。"但AI代理通过API交互。它们看不到某人何时在打字,也不会自己触发打字指示器。所以你得到这样的情况:
  1. 用户:嗨,我有个问题
  2. 用户:是关于我的订单的
  3. 用户:上周的那个
  4. AI[已经在回应第一条消息]
有些用户在一则消息中写小说。其他人像摩尔斯电码一样发送想法——嗒、嗒、嗒。经过几周的实验,我仍然没有完美的解决方案。你是等待每条消息后的几秒钟看看是否还有更多消息?你是分析消息长度模式?你是寻找暗示完成的语言线索?
文化轮换发言
我从自己的多语言背景中注意到一些有趣的事情。在哈萨克斯坦长大,然后在国外学习和工作,我体验了不同文化如何处理对话暂停。
在西班牙对话中,人们经常重叠——这不是粗鲁,这是投入。在哈萨克斯坦,那些较长的暂停并不尴尬:它们是尊重的。现在想象编程一个系统来处理两种风格。3秒的暂停可能在一个文化中表示"我说完了",在另一个文化中表示"我在思考"
到目前为止我找到的最佳解决方案结合了多种策略:
寻找语言完成标记
在回复前等待固定时间
当不可避免地过早回应时,优雅地处理中断
这种优雅处理错误的关注让我想到了构建对话AI代理最重要的教训。
优雅失败的艺术
《与事物对话》向我介绍了"修复"或我称之为恢复的概念。人类对话经常偏离轨道,但我们几乎无意识地一起修复它们。我们澄清,我们回溯,我们一笑置之。
你的AI会失败。不是偶尔,而是经常。问题不是如何防止失败;而是如何从失败中恢复。
让我给你一个理论例子。想象一个食品配送服务的AI代理。客户说他们点了"老样子",但系统没有之前订单的记录(无论什么原因)。代理可能会崩溃并说"我不理解'老样子'",或者它可以优雅地恢复:"我很乐意给你拿老样子!你能提醒我那是什么吗?我想确保我准确地拿到你的订单。"
区别?一个让客户感到沮丧(让AI代理显得愚蠢),另一个让他们感到被倾听,同时顺利地获得所需信息。
💡 如果你处理恢复得当,人们对AI错误出奇地宽容。
这不仅仅是关于有几个现成的"抱歉"回应。这是关于将恢复构建到每次交互中:
承认:不要假装错误没有发生
同理心:表明你理解不便
幽默(在适当的时候):一点自嘲大有帮助
行动:实际修复问题或提供替代方案
一旦你掌握了恢复,你需要考虑到底是谁在做恢复——这就是个性发挥作用的地方。
明确定义的个性不是可选的
构建对话AI代理不仅仅是使用LLM生成正确的回应。我们都能注意到与Amazon Alexa、Apple Siri、ChatGPT、Yandex Alice(甚至Claude Chat / Mistral LeChat——任何人?)交互时的差异,但我们通常无法明确说出实际差异是什么。然而,我们都感知到这些助手有不同的个性,这些个性是由开发者和设计师准确构建的,让我们人类感到独特。
人们从一系列事物中推断个性:词汇选择、声音(声音)和行为(下一节更多关于这个)。这里有让我惊讶的东西:你给AI代理的个性从根本上改变了用户与它的交互方式。这不是让你的机器人"有趣""古怪"。这是关于创建一致的、可预测的交互,用户可以适应。
这被称为"适应""镜像"——人们如何自然地调整他们的沟通风格以匹配他们的对话伙伴。我注意到用户实际上开始镜像代理的沟通风格。正式的代理得到正式回应。友好的代理得到友好回应。就像看一场舞蹈,一个伙伴微妙地引导,另一个跟随。
行为和意图是关键
技巧不是写模糊的指令如"友好和专业"。而是为特定情况定义特定行为,从这些行为中涌现出你的系统需要处理的意图。
但首先,什么是意图?在对话AI中,意图代表用户想要完成什么或系统应该采取什么行动。不是试图处理用户输入的无限变化,你定义特定的意图集来捕获你的代理可以执行的核心行动。
从模糊提示到特定意图
这是许多开发者做错的地方。他们写这样的提示:
  1. 你是一个有用的客户支持代理。要有同理心且专业。
这太模糊了。"有同理心"在实践中意味着什么?相反,定义创造同理心的特定行为。
例如,当你希望代理"有同理心"时,你实际上想要的是"在提供解决方案之前总是承认客户情绪"的行为。
这种行为自然地导致创建这样的意图:
  1. class AcknowledgeEmotion(BaseModel):
  2. """识别和验证客户感受"""
  3. emotion_type: Literal["frustrated", "confused", "happy", "angry"]
  4. intensity: Literal["mild", "moderate", "severe"]

  5. class RequestClarification(BaseModel):
  6. """当问题不清楚时询问更多细节"""
  7. unclear_aspect: str
  8. suggested_questions: list[str]
python
这些意图来自于定义代理在情绪情况下应该如何行为。期望的行为驱动技术实现,而不是相反。
条件意图
意图也可以根据上下文有条件地可用。对于处理免费和付费用户的客户支持代理,我们可以为付费用户添加RedirectToHuman意图,为免费用户添加CannotRedirectToHuman意图。
  1. if user.account_type == "paid":
  2. intents.append(RedirectToHuman)
  3. else:
  4. intents.append(CannotRedirectToHuman)
python
这防止代理向还没有购买任何东西的人承诺人工支持,同时仍然让它解释为什么它不能帮助某些请求。
有用的意图示例
以下是一些我发现有用的意图示例:
AcknowledgeEmotion:识别和验证用户感受
RequestClarification:当信息不完整时询问更多细节
ProvideSolution:提供具体的解决方案或步骤
EscalateToHuman:将复杂问题转给人工代理
ConfirmAction:在采取行动前确认用户意图
ProvideAlternative:当首选解决方案不可用时提供替代方案
回到基础:简单的循环
经过所有这些关于对话设计、个性和意图的讨论,你可能想知道技术实现是什么样的。
答案是:一个简单的循环。没有LangChain,没有CrewAI,没有新的花哨框架。
我深受Anthropic的代理定义和HumanLayer的12因子代理原则的影响。两者基本上说同样的事情:代理只是在一个循环中使用工具的模型。
Anthropic的定义:
  1. env = Environment()
  2. tools = Tools(env)
  3. system_prompt = "Goals, constraints, and how to act"

  4. while True:
  5. action = llm.run(system_prompt + env.state)
  6. env.state = tools.run(action)
python
HumanLayer的定义:
  1. initial_event = {"message": "..."}
  2. context = [initial_event]
  3. while True:
  4. next_step = await llm.determine_next_step(context)
  5. context.append(next_step)

  6. if next_step.intent == "done":
  7. return next_step.final_answer

  8. result = await execute_step(next_step)
  9. context.append(result)
python
这是相同的模式:观察上下文,决定行动,执行,更新状态,重复。就是这样。其他一切都是实现细节。
回到基础
这个旅程有某种美丽的讽刺。当我在训练营教授Python数据科学时,第一个概念之一是循环:
  1. for item in items:
  2. process(item)
python
简单,对吧?但当你进入数据分析(pandas, numpy)时,你花几周时间学习避免循环。"永远不要遍历DataFrame行!"我们会说。"使用向量化操作!"
现在有了AI代理,我们回到了最基本的模式:
  1. while not done:
  2. observe()
  3. think()
  4. act()
python
有时最古老的模式是最好的模式。这有某种诗意——我们拥有的最先进的AI技术,运行在最基本的编程结构上。
为什么不使用框架?
当你使用框架构建代理时,你在这个简单循环上添加了抽象层。这些框架是为最大灵活性而构建的——它们需要处理从聊天机器人到自主研究代理的每个可能的用例。
但当你只有一个特定的用例和特定需求时,比如:
每个决策的细粒度监控
精确的对话流程控制
对话特定边缘情况的自定义错误处理
与你的特定通信渠道和特定技术栈的集成
...那些抽象变成了障碍。你花更多时间与框架斗争而不是解决实际问题。
根据HumanLayer的研究,大多数构建生产代理的公司最终都会自己构建。在尝试两种方法后,我理解为什么。复杂性不在代理循环中——它在你的对话设计、意图和错误处理以及集成需求中。框架无法抽象这些。
使用第一原理的客户支持代理
我们之前一直在讨论客户支持代理作为例子。
从第一原理和对话设计理念,这是草稿实现:
  1. continue = True
  2. while continue:
  3. intents = llm.determine_intents(context)
  4. context.append(intents)

  5. action = process_intents(intents)

  6. if action.is_final = True:
  7. continue = False

  8. result = await execute_action(action)
  9. context.append(result)
python
示例流程
让我们通过两个场景来看看这是如何工作的:
简单FAQ示例 - "如何取消我的订阅?"
在客户支持中总是有一组用户最常问的问题,称为FAQ。我们可以将FAQ预加载到LLM提示中,这样代理可以立即回应。
代理确定意图:ReplyToUser
处理这个意图,结果发送消息。发送消息的行动是最终的,所以循环将在执行后结束
通过API发送此消息来执行行动
用此消息更新上下文(对话历史)
复杂示例 - "我的订阅何时续费?"
代理确定意图:FetchUserSubscriptionData
执行订阅数据获取
用用户的续费日期更新上下文
循环继续,上下文现在包含用户数据
代理确定意图:ReplyToUser
生成并发送带有确切日期的个性化回应
标记行动为最终,循环结束
美妙之处在于更复杂的场景只是意味着更多循环迭代,而不是根本不同的代码。
上下文就是一切
对话AI代理开发的最后一块是上下文工程
这个术语由HumanLayer的Dex创造,最近获得了Shopify CEO Tobi Lütke甚至Andrej Karpathy的认可而获得关注。
相同的用户消息根据上下文意味着完全不同的事情。
用户:"是的"
没有上下文,这是无意义的。有了上下文:
"你想看我们的菜单吗?"之后 用户想要浏览选项
"这是你当前的地址吗?"之后 用户正在确认信息
"我应该取消你的订单吗?"之后 用户想要取消
考虑以下场景,其中上下文工程不仅仅是提示工程:
客户支持团队的某人试图就问题给用户打电话,但电话失败了。我们可以记录该事件并将其添加到我们的客户支持代理的上下文中。
然后我们的客户支持代理在自己的上下文中看到这个,并自然地用适当的意图承认它:"嘿,看起来我们之前试图给你打电话但联系不上你。现在打电话更好吗?"
用户确认后,客户支持团队的人再次打电话,所有对话都被转录和保存。
如果我们将此转录传递给客户支持代理的上下文,那么代理可以说"正如你昨天在电话中与...讨论的那样"
像这样制作上下文让体验感觉连贯。
关键要点
我在这段旅程中还很早。每天都会带来新的边缘情况、新的失败需要恢复、新的模式需要识别。但这是我到目前为止的学习:
对话设计 > 技术复杂性:理解轮换发言、文化差异和恢复策略比最新框架更重要
恢复 > 完美:如果你优雅地处理错误,用户会原谅错误。将恢复构建到每次交互中。
上下文 > 功能:具有丰富上下文的简单代理胜过没有上下文的复杂代理
简单循环 > 复杂框架:大多数生产代理只是具有良好意图处理的while循环
行为驱动实现:首先定义特定行为,然后从中派生技术意图
对话AI的未来不在复杂框架或越来越大的模型中。它在于理解对话、上下文和人类交互的基础。它在于构建优雅失败、适应用户并记住在一天结束时,它们正在与一个只想被理解的人类进行对话的系统。
有时,这就像知道何时倾听的while循环一样简单。
这些想法基于构建生产代理的个人经验。所有示例都是说明性的,任何观点都是我自己的——不是我雇主的。如果你正在构建对话AI,我很想听听你的想法。你是团队框架还是团队从头开始?
关键词:AI代理、对话设计、LLM、自然语言处理、用户体验、技术架构