暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

技术科普|如何用 Python 实现 Coding Agent

NebulaGraph 2025-10-22
210

导读


在 技术科普「Coding Agent」系列中,由 NebulaGraph GenAI Team @PsiACE 为大家带来多期 Coding Agent 实践经验,并分享 NebulaGraph GenAI 的最新工作。欢迎在评论区和 @PsiACE 交流,知无不言~

本期,@PsiACE 分享的是如何用 Python 实现一个能自举的 Coding Agent,并给出了避坑指南,希望给大家的 Coding Agent 带来启发。

Bub 的第一个 milestone:自动修类型注解。由 Moonshot K2 驱动。

Bub: Successfully fixed the first mypy issue by adding the missing return type annotation -> Noneto the __init__method in src/bub/cli/render.py, reducing the error count from 24 to 23.


01

为什么要自己造 Agent?

Coding Agent 现在已经是个红海赛道,市面上有不少优秀的产品,还有许多团队在 PPT 中绘制宏伟蓝图。

然而,Coding Agent 的“token 大力出奇迹”现象也很明显——动辄几十万 token 的消耗,真正有价值的部分却少之又少。

这让我很好奇:如果自己动手造一个 Coding Agent,能不能找到更高效、更实用的解决方案?

于是,我开始折腾一个叫 Bub 的 CLI 助手。它的目标很简单:做一个命令行下的实用助手,同时具备有限的自举能力。自举这个概念在编译器、操作系统领域早已不算新鲜,很多 Coding Agent 也喜欢宣传“AI 工程师贡献了多少代码”。

我希望 Bub 能迈出自己的第一步,解决它自身代码中的第一个实际问题。


02

最小可用:先跑起来再说

我的经验是,能跑起来的最小闭环最重要,别一上来就追求“完美架构”或者花太多时间做数据小偷。

Bub 的分层很简单:

  • Agent:主循环,负责 LLM 交互、工具调用、上下文管理。
  • Tool:每个工具一个类,参数用 Pydantic 校验。
  • ToolRegistry:注册所有工具,方便扩展。
  • CLI:Typer + Rich,命令行入口,支持展开中间状态。

Agent 的本质其实就是一个 while 循环。每次循环,Agent 会根据当前上下文判断是否需要调用工具,如果需要就调用,然后把工具的返回结果写回上下文。

主循环核心代码

    class Agent:
        def chat(self, message: str) -> str:
            self.conversation_history.append(Message(role="user", content=message))
            while True:
                # Construct context: historical messages + tool list
                ...
                response = litellm.completion(...)
                assistant_message = str(response.choices[0].message.content)
                self.conversation_history.append(Message(role="assistant", content=assistant_message))
                tool_calls = self.tool_executor.extract_tool_calls(assistant_message)
                if tool_calls:
                    for tool_call in tool_calls:
                        result = self.tool_executor.execute_tool(tool_call.name, **tool_call.parameters)
                        observation = f"Observation: {result.format_result()}"
                        self.conversation_history.append(Message(role="user", content=observation))
                    continue
                else:
                    return assistant_message

    踩过的坑

    • 没有捕获,LLM 输出格式一变就死循环
    • 工具参数没校验,LLM 乱传参数直接崩
    • Observation 反馈太长或缺乏有效信息,LLM 理解困难

    03

    工具定义:扩展 LLM 的能力

    工具是 LLM 和外部世界的桥梁,定义得好,模型才能真正“动手”。我的做法是:

    • 工具参数全部用 Pydantic 校验,类型不对直接拒绝。
    • 命令行工具有黑名单(比如 rm
      、del
      ),遇到危险命令直接报错。
    • 工具执行结果结构化返回,别让 LLM 猜。
    • 操作命令行工具时,stdout 和 stderr 都很重要,不能只给 exit code.
    • 工具之间要有明确边界,避免混淆。
      class RunCommandTool(Tool):
          DANGEROUS_COMMANDS = {"rm", "del"}
          def _validate_command(self, base_cmd: str) -> Optional[str]:
              if base_cmd in self.DANGEROUS_COMMANDS:
                  return f"Dangerous command blocked: {base_cmd}"
          def execute(self, context: Context) -> ToolResult:
              # Validate command, execute and return results


      04

      Prompt:让 LLM 按套路出牌

      组织良好的提示词能显著提升 LLM 的输出质量。对于 Coding Agent 来说尤其重要,因为 LLM 的输出格式很容易失控。

      我的经验

      • Prompt 里要列出所有工具和参数 schema。
      • 多给几个调用示例,覆盖常见用法。
      • Observation 反馈要简洁,别堆无用信息。

      Bub 的 ReAct Prompt 结构

        You are an AI assistant with access to tools. When you need to use a tool, follow this format:
        Thought: ...
        Action: run_command
        Action Input: {"command": "ls"}
        Observation: <output>
        ...
        Final Answer: <your answer>

        ReAct 的好处是简单直接,容易落地,虽然 token 消耗大,但能快速试错、跨模型迁移。


        05

        Milestone:自动修类型注解

        定义好 Agent Loop、工具和 Prompt 后,Bub 的第一个 milestone 就是自动修复了一个 mypy 报错。

        比如:

          -    def __init__(self):
          -        self.console = Console()
          -        self._show_debug = False
          +    def __init__(self) -> None:
          +        self.console: Console = Console()
          +        self._show_debug: bool = False

          实际的 Agent Loop

          • 只让 agent 改类型注解、格式化、重命名,别让它碰复杂逻辑。
          • 先用命令行工具执行 mypy
            ,拿到报错信息。
          • 让 agent 生成修复建议,再用 file edit 工具应用到代码。
          • 修完自动再跑一次 mypy,确保没新问题。

          踩过的坑

          • 模型对代码上下文理解有限,经常修错。
          • 不验证,bug 越修越多。

          06

          进阶玩法与工程自查

          随着功能扩展,踩的坑也越来越多。我的一些经验:

          • 工具扩展时,建议单一职责,参数 schema 明确。
          • 长对话要截断或摘要,别让 LLM 超窗。
          • 生产环境建议沙箱/虚拟机,命令行工具默认禁危险命令。
          • LLM 输出格式不稳时要有 fallback 兜底。


          07

          总结

          Bub 还在早期,但已经能帮我自动修 bug、跑命令、读写文件。我希望这只是一个开始,然后得到更多有意思的反馈。

          Bub it. Build.it

          项目地址

          https://github.com/PsiACE/bub

          References

          • https://ampcode.com/how-to-build-an-agent

          • https://huggingface.co/blog/tiny-agents

          欢迎关注 @PsiACE 的公众号⬇️



          ✦

          如果你觉得 NebulaGraph 能帮到你,或者你只是单纯支持开源精神,可以在 GitHub 上为 NebulaGraph 点个 Star!

          每一个 Star 都是对我们的支持和鼓励✨

          GitHub:https://github.com/vesoft-inc/nebula

          官网:https://www.nebula-graph.com.cn/

          论坛:https://discuss.nebula-graph.com.cn/


          ✦

          ✦


          扫码添加

           可爱星云

          技术交流

          资料分享


          NebulaGraph 用户案例

          ✦

          Why Graph Database?⬇️

          复杂关系场景,图数据库为何是首选?

          风控场景:普适智能|中证数智|BlockSec|携程|Airwallex|众安保险|中国移动|Akulaku|邦盛科技|360数科|BOSS直聘|金蝶征信|快手|青藤云安全

          平台建设:博睿数据|携程|众安科技|微信|OPPO|vivo|美团|百度爱番番|携程金融|普适智能|BIGO

          知识图谱:普适智能|中证数智|中医药大学|企查查|腾讯音乐|中科大脑|泰康在线|苏宁|微澜|同花顺|携程酒店

          数据血缘:波克城市|微众银行|携程金融

          智能运维:BOSS直聘|58同城|中亦安图

          供应链:京东物流|震坤行

          营销推荐:阿里妈妈

          GraphRAG:中科数睿

          ✦

          ✦

          ✨ NebulaGraph 推荐阅读

          文章转载自NebulaGraph,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

          评论