动机
LLM 如何与系统中的环境交互?它不会。它是一个调用和响应 API。我经常听到 Agent 说这说那,但在我看来,如果 Agent 没有工具来观察或操纵其环境,那么它在执行我们关心的那些有意义的任务时就会受到根本性的限制。
最初十次看到新的流行词,我都会尽量忽略它,但自从**模型上下文协议 (MCP)**不断出现后,我开始认真研究它。MCP 提供了一种统一的格式来宣传工具和资源的存在及其使用方法,巧妙地解决了这个问题。当你需要为 LLM 构建一个连接到工具或数据库的新连接器时,你可以找到一个预先构建的开源 MCP 服务器并将其导入。MCP 还有一个企业赞助商——Anthropic ,它是行业的主要参与者之一——来维护它,因此它从第一天起就经过了“狗粮”测试(dogfooded),并且经久耐用。
Related MCP server: Zaturn
计划
我喜欢通过解决实际问题来自学新知识——我发现这样结果更容易被记住。我做了大量的检索增强生成 (RAG) 工作,其中很多正在准备开源,我认为 MCP 是 RAG 架构的下一个发展方向。我认为在不久的将来,如果你能很好地完成 RAG,那么你就会将其建立在 MCP 之上。
最近我一直在学习房地产投资,预计未来一两年内市场会出现回调。我打算将一些免费的 Zillow 数据加载到数据库中,然后在其上运行一个 MCP 服务器。之后,我将运行一个 FastAPI 服务器,连接到 MCP 服务器,并处理来自 HTML 界面的请求。最终目标是开发一个聊天机器人,帮助我探索这些房地产数据,并决定在哪些市场寻找交易机会。
我要加载的数据包括:
Zillow 房屋价值指数 (ZHVI) –衡量特定地区和住房类型的 65 至 95 百分位数内的典型房屋价值。
Zillow 房屋价值预测 (ZHVF) –根据当前和历史市场数据对房屋价值趋势进行前瞻性估计。
Zillow 观察租金指数 (ZORI) –对当前和非市场租赁清单中观察到的典型市场租金的平滑衡量。
Zillow 观察租金预测 (ZORF) –根据 ZORI 和市场指标的趋势预测租金价格的变化。
您可能注意到我排除了 ZHVI 数据,这是由于缺乏数据 - 他们最近才开始跟踪这一点。
这是非常特定领域的数据 - 您可能不想在没有阅读定义的情况下对数据进行猜测 - 所以我认为这将是一个很好的例子,因为 LLM 无法通过一组简单的问题直观地了解它的方式。
我想请法学硕士帮我找到一个市场,那里既有价格合理的房屋,租金收入稳定,而且未来增长率很高。我也不想把这些预测增长率视为理所当然——让我们来编程一下,看看它们在哪些领域更符合预期。我预计这需要大量的快速工程来编写不同的查询。然后,我可以将这些提示存储为 MCP 提示,以便向聊天机器人提出建议并在数据库中执行。
我选择 SQLite 作为数据库,因为它将内存存储在本地文件中,因此无需重新加载或启动/关闭数据库。为了便于移植,我将在容器中运行数据库,因此将数据库状态保存在文件中意味着我可以根据需要将其视为“缓存”数据加载。这样,如果我挂载到本地卷,就无需每次重启容器时都将 Zillow 数据重新加载到数据库中。
为了能够处理这些数据,我知道我需要编写某种 MCP 服务器,它可以针对我们刚刚编写的表运行查询。根据我目前所读到的内容,我认为我应该将有用的查询编码为 MCP 提示或工具,然后将其呈现给 MCP 客户端背后的 LLM,但我真的不确定实际操作起来会是什么样子。我首先参考了langchain 的这份文档,并结合了一些我读过的其他资料,作为我构建的入门服务器。然后,我主要遵循Anthropic 的文档来编写我的 MCP 客户端的启动程序,尽管我将他们的大部分代码替换成了 langgraph ReAct 代理。之后,我不确定如何让客户端和服务器相互通信,所以我找到了一份非常棒的 MCP 文档,其中介绍了 MCP 内置的各种传输方法。我将采用默认方法,即使用 stdio 在客户端和服务器之间进行进程内消息传递。这将是一个包含本地数据库和应用程序后端的单一容器,所以这很合理。但对于任何生产级应用,我设想 MCP 服务器应该与后端解耦,这将需要更复杂的 HTTP 流配置。等我需要为工作构建类似的东西时再考虑这个问题。
目前,这只是我为生成单条消息而执行的一个脚本。为了使其可用,我需要连接一个 Web 服务器,该服务器接收用户查询并通过这些函数运行它们。为了使 Web 服务器可用,我需要一个看起来像聊天界面的前端来向服务器发出请求。Streamlit 最近在类似的 AI 项目中风靡一时,我也在之前的项目中以及工作中的内部工具中尝试过它,但我得出结论,用缓慢的 Python 代码运行缓慢的 React 代码,需要为 Python 部署一整段额外的服务器代码,这不是构建轻量级前端的最佳方式。没有人愿意在概念验证获得批准后将其重写成真正的生产级代码,所以很多时候这似乎根本不可能发生。我编写过很多 React 代码,这可以省去 Python 中间件,但这真的感觉有点矫枉过正。每次我构建全栈项目时,我最终做的前端开发工作都比我实际想要学习的要多。 HTMX 在我的雷达上已经关注了一段时间,我打算在这个项目里尝试一下——它轻量级到爆,提供了像聊天应用这样低逻辑前端所需的极简功能。而且,这些表情包也非常优秀。这对我的服务器选择唯一的影响是我需要返回模板化的 HTML,所以我打算用 Jinja 来模板化我的网页,并用 HTMX 脚本标签发送。这真的就是运行它所需的全部内容,太棒了。
不过,Echo 服务器其实没什么用,所以让我们插入 LLM 代理。我将 MCP 客户端添加到 FastAPI 服务器的生命周期中,并将其绑定到应用状态,以便它能够以线程安全的方式在各个工作线程之间传递,而客户端/服务器并非基于池化构建的。我们只需将消息传递给代理,并将输出格式化为一段小的 HTML 代码,然后将其传回 UI。