最近一段时间,我看了不少 AI 项目。

有些项目界面做得很漂亮,打开之后却还是熟悉的流程:输入一个问题,模型返回一段文字。刚开始确实觉得新鲜,但用不了多久就会发现,它和普通聊天工具没有太大区别。

我一直想做一个更实用的东西:能不能让 AI 自己查资料、看日志,发现问题后顺手创建一张工单?

于是我动手做了一个简单的技术助手。

整个项目并不复杂,但做完之后,我对 AI 应用开发有了一个比较明显的感受:大模型真正有价值的地方,可能不是“知道很多”,而是能够接入我们已有的系统。


先说说这个助手能做什么

我给它设计了一个很常见的场景。

用户输入:

订单服务今天经常超时,帮我看看是什么原因。
如果确认是线上故障,再创建一张工单。

普通聊天机器人只能根据经验猜测:

可能是数据库压力过大,也可能是网络延迟,建议检查日志。

这类回答不能说错,但基本等于没说。

我希望助手完成的是下面这些事情:

  1. 从内部知识库中查询订单服务的相关文档;
  2. 调用日志接口,读取最近一段时间的错误日志;
  3. 根据真实日志判断问题原因;
  4. 判断是否达到线上故障标准;
  5. 符合条件时调用工单接口;
  6. 把分析过程和处理结果告诉用户。

实际运行起来,大致是这样的:

收到问题
  ↓
查询相关技术文档
  ↓
读取订单服务日志
  ↓
发现数据库连接池耗尽
  ↓
判断故障等级
  ↓
创建工单
  ↓
返回结果

做到这一步,AI 才算从“给建议”变成了“帮忙处理问题”。


第一步:先让 AI 看得懂内部资料

大模型知道很多公开知识,但它不可能知道我们项目里的接口设计、部署方式和历史故障。

我最开始犯过一个错误:直接把大量项目文档塞进提示词。

文档少的时候还能用,内容一多,响应速度和效果都会变差。更麻烦的是,模型经常抓不住真正重要的内容。

后来我换成了 RAG,也就是检索增强生成。

这个名字听起来有点复杂,实际思路非常直白:

不要一次性把所有资料都交给模型。先找到与问题有关的几段内容,再让模型阅读。

处理流程如下:

用户问题
  ↓
把问题转换成向量
  ↓
从知识库中找出语义相近的文档
  ↓
把相关文档和问题一起发给模型

例如,知识库中有下面几段内容:

documents = [
    "订单服务使用 Redis 保存热点商品的库存信息。",
    "订单接口出现大量超时时,需要优先检查数据库连接池。",
    "线上故障达到 P1 级别后,需要立即创建故障工单。"
]

写入知识库时,先把文字转换成向量:

for document in documents:
    vector = embedding_model.embed(document)

    vector_database.insert({
        "content": document,
        "vector": vector
    })

用户提问后,用相同的方式生成问题向量:

def search_knowledge(question):
    question_vector = embedding_model.embed(question)

    return vector_database.search(
        vector=question_vector,
        top_k=3
    )

向量检索的好处是,它不要求用户必须说出文档中的原词。

用户说“下单特别慢”,文档中写的是“订单接口超时”,两句话不完全一样,但语义接近,仍然有机会被检索出来。

当然,RAG也不是接上向量数据库就万事大吉。

我在实际测试时发现,文档怎么切分非常重要。切得太长,模型会收到很多无关信息;切得太短,上下文又容易断掉。

目前我的做法是:

  • 按标题和段落切分,尽量不破坏完整语义;
  • 每段保留来源、更新时间和所属项目;
  • 检索后再进行一次相关性排序;
  • 找不到可靠资料时,明确告诉用户,而不是让模型自己补充。

最后一点尤其重要。AI 最麻烦的情况不是“不知道”,而是不知道的时候仍然给出一个看起来很确定的答案。


第二步:让 AI 学会调用工具

接入知识库后,助手能够阅读内部资料了,但它仍然无法查询实时日志,也不能创建工单。

这时候就需要 Function Calling。

可以把它理解成:我们先告诉模型“你有哪些工具可以使用”,然后由模型判断什么时候使用、传入哪些参数。

例如,我给助手提供了一个日志查询工具:

tools = [
    {
        "name": "query_service_logs",
        "description": "查询指定服务最近一段时间的错误日志",
        "parameters": {
            "type": "object",
            "properties": {
                "service_name": {
                    "type": "string",
                    "description": "需要查询的服务名称"
                },
                "minutes": {
                    "type": "integer",
                    "description": "查询最近多少分钟的日志"
                }
            },
            "required": ["service_name", "minutes"]
        }
    }
]

模型分析用户的问题后,可能返回这样的调用参数:

{
  "name": "query_service_logs",
  "arguments": {
    "service_name": "order-service",
    "minutes": 30
  }
}

需要注意的是,模型并没有直接访问日志系统。

它只是告诉我们的程序:“我认为现在应该调用这个工具,参数是这些。”真正执行查询的,仍然是我们自己编写的代码:

def query_service_logs(service_name, minutes):
    # 实际项目中,这里会请求日志平台
    return {
        "service": service_name,
        "error_count": 236,
        "main_error": "Database connection pool exhausted",
        "average_latency": "4.8s"
    }

程序再把查询结果交还给模型,模型继续分析:

订单服务最近30分钟出现236次错误,
主要错误为数据库连接池耗尽,
接口平均响应时间为4.8秒。

这样一来,模型的判断就不再完全依赖猜测,而是有了真实数据。


真正费脑筋的地方:让它连续完成任务

一开始,我以为给模型配置几个工具就结束了。

真正写起来才发现,工具调用只是第一步。一个任务通常不可能通过一次调用完成。

比如处理订单服务超时,需要经历:

查知识库 → 查日志 → 分析结果 → 判断等级 → 创建工单

每一步都依赖上一步的结果。

于是还需要给它加一个执行循环:

def run_agent(user_input):
    messages = [
        {
            "role": "system",
            "content": """
你是一名运维助手。
请结合知识库和可用工具处理问题。
不能根据现有信息确认的内容,需要明确说明。
"""
        },
        {
            "role": "user",
            "content": user_input
        }
    ]

    for step in range(8):
        response = llm.chat(
            messages=messages,
            tools=tools
        )

        if response.has_tool_call():
            tool_name = response.tool_name
            arguments = response.arguments

            tool_result = execute_tool(
                tool_name,
                arguments
            )

            messages.append(response.to_message())
            messages.append({
                "role": "tool",
                "name": tool_name,
                "content": json.dumps(tool_result)
            })

            continue

        return response.content

    return "执行步骤过多,任务已经停止。"

这段代码做的事情可以概括为:

  1. 模型查看当前已有的信息;
  2. 模型决定下一步要不要调用工具;
  3. 程序执行工具;
  4. 执行结果交回模型;
  5. 模型根据新结果继续判断;
  6. 没有工具需要调用时,输出最终答案。

这种“看结果,再决定下一步”的循环,才是整个智能体比较关键的部分。

不过,也正是从这里开始,问题逐渐多了起来。


AI 有时候会“太勤快”

测试过程中,我遇到过一个很有意思的情况。

我让助手查询一次日志,它查询完之后觉得信息不够,又查了一次。第二次结果回来后,它换了一个时间范围继续查。再不限制,它很可能一直查下去。

还有一次,模型连续两次调用了创建工单接口,差点生成两张完全相同的工单。

所以,智能体不能只考虑“能不能完成任务”,还要防止它把事情做过头。

我最后加了几层限制。

限制最大执行次数

MAX_AGENT_STEPS = 8

超过最大步骤后直接停止,避免模型陷入循环。

防止重复调用

execution_key = hash(
    tool_name + json.dumps(arguments, sort_keys=True)
)

if execution_key in executed_operations:
    raise RuntimeError("检测到重复操作,本次调用已停止")

校验模型生成的参数

def validate_tool_arguments(tool_name, arguments):
    if tool_name == "query_service_logs":
        minutes = arguments["minutes"]

        if minutes < 1:
            raise ValueError("查询时间必须大于0")

        if minutes > 1440:
            raise ValueError("单次最多查询24小时")

模型生成了参数,并不代表参数一定合理。

工具的参数校验、权限校验和业务规则,仍然应该写在正常的程序代码里。不能因为接入了大模型,就把原来的安全机制全部交给它。


涉及真实操作时,别让 AI 自己拍板

查询文档和读取日志属于低风险操作,可以自动执行。

但重启服务、删除数据、发送外部邮件就完全不同了。

我的处理方式是给工具划分风险等级:

HIGH_RISK_TOOLS = {
    "delete_database_record",
    "restart_production_service",
    "send_external_email"
}

当模型准备调用高风险工具时,程序不会立即执行,而是返回确认信息:

if tool_name in HIGH_RISK_TOOLS:
    return {
        "status": "waiting_confirmation",
        "message": "该操作风险较高,请确认后继续执行。"
    }

也就是说,AI 可以提出建议,可以准备好参数,但最后一步由人确认。

这个过程可能让自动化看起来没有那么“炫”,却更适合真实项目。

毕竟线上系统最怕的不是 AI 不够聪明,而是它非常自信地做错了一件事。


我还加了一个专门“挑刺”的 AI

为了减少错误,我做了一个小尝试:让另一个模型专门检查第一个模型的结果。

第一个智能体负责处理任务:

查资料、调工具、分析问题、生成方案

第二个智能体不执行操作,只负责检查:

证据是否充分?
结论是否和日志一致?
有没有遗漏风险?
是否执行了用户没有授权的操作?

简化后的代码如下:

solution = executor_agent.run(task)

review = reviewer_agent.run({
    "task": task,
    "solution": solution,
    "check_items": [
        "结论是否有日志或文档支持",
        "是否把推测当成了事实",
        "是否遗漏潜在风险",
        "是否执行了未经授权的操作"
    ]
})

if review["passed"]:
    return solution

return executor_agent.revise(
    original_solution=solution,
    review=review
)

这个设计并不能保证结果百分之百正确,第二个模型同样可能判断失误。

但在我的测试中,它确实能发现一些问题,比如:

  • 日志只显示连接池不足,回答却直接认定是慢 SQL;
  • 工具调用失败了,最终回答却说工单已经创建;
  • 知识库文档已经过期,回答时没有提醒用户;
  • 模型给出了结论,却没有说明依据。

它有点像开发过程中的 Code Review:不一定能拦住所有问题,但多一道检查通常比没有好。


关于“记忆”,我没有保存全部聊天记录

很多 AI 产品都在强调长期记忆。我最初也想把所有对话全部保存下来,后来发现这样做不太合适。

聊天记录越来越多以后,会出现几个问题:

  • 发送给模型的内容太长;
  • 旧信息可能已经失效;
  • 用户偶然提到的一句话,不一定代表长期偏好;
  • 保存过多内容还会带来隐私问题。

所以,我只保存相对稳定、确实对后续任务有用的信息,例如:

{
  "preferred_language": "Python",
  "deployment_environment": "Docker + Linux",
  "answer_style": "先给结论,再说明原因"
}

历史问题则以摘要形式保存:

{
  "problem": "订单服务数据库连接池耗尽",
  "solution": "排查慢查询并调整连接池配置",
  "result": "服务恢复",
  "recorded_at": "2026-07-20"
}

下次遇到类似问题时,通过向量检索找出相关记录,不需要把全部历史对话重新发送一遍。

我的理解是,AI 记忆不是保存得越多越好,而是要知道什么值得记、什么时候应该忘。


项目结构不要全塞进一个文件

这种项目刚开始可能只有几百行代码,很容易把提示词、工具和模型调用全部写进一个文件。

工具增加后,维护起来会非常痛苦。

我后来按照职责做了拆分:

ai-agent/
├── api/                 # 对外接口
├── agents/              # 智能体执行逻辑
│   ├── executor.py
│   └── reviewer.py
├── tools/               # 日志、工单等工具
│   ├── log_tool.py
│   └── ticket_tool.py
├── rag/                 # 知识库检索
│   ├── embedding.py
│   └── retriever.py
├── memory/              # 用户偏好和历史经验
├── prompts/             # 提示词
├── security/            # 权限、参数和风险校验
└── main.py

提示词最好也单独管理。

提示词在 AI 项目中的作用有点像代码,但又不像普通代码那么稳定。模型升级、工具变化或者业务规则调整,都可能影响最终效果。把它散落在业务代码中,后面很难测试和修改。


做完之后,我对 AI 编程有了一点不同的看法

以前我觉得 AI 应用开发主要是“研究提示词”。

真正做了一个能调用工具的项目后,我发现提示词只占其中一部分。大量工作仍然是传统软件开发:

  • 接口设计;
  • 参数校验;
  • 权限控制;
  • 异常处理;
  • 日志记录;
  • 重试和超时;
  • 调用成本控制;
  • 结果评估。

不同之处在于,传统程序的执行路径通常由开发者提前写好:

if error_count > 100:
    create_ticket()

而智能体会根据上下文、工具结果和任务目标,动态决定下一步做什么。

这种灵活性很有吸引力,但也会带来不确定性。我们需要做的,不是完全消除这种不确定性——那几乎不现实——而是把它限制在一个可接受的范围内。


最后

如果你也想做一个 AI 项目,我不太建议停留在简单的聊天页面。

可以尝试给模型接入一个真实场景:

  • 读取项目文档;
  • 查询数据库;
  • 分析运行日志;
  • 生成测试用例;
  • 整理代码审查意见;
  • 调用工单或消息接口。

哪怕只接入一两个工具,项目带来的体验也会完全不同。

这个技术助手目前还有不少问题,例如复杂任务成功率不稳定、长流程调用成本较高、知识库内容需要持续维护。但至少它已经不只是生成一段“正确但没什么用”的文字了。

它开始能够根据真实信息,帮我完成一些具体工作。

对我来说,这才是 AI Agent 最值得继续折腾的地方,体验点击下方下载,软件比较大安装比较慢。

蜗牛智能体以大模型为核心的办公智能体:自然语言驱动、零技术门槛、任务自动执行并交付结果。多模式(问答/执行/配置/自主)、多智能体协同、技能库与 IM 通道。数据留在本机,可选云端同步。https://snailagent.com/


Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐