Delphi程序和AI大模型交互

使用 Delphi 写AI大模型的 Agent

简单的概念解释

所谓的 Agent 是执行在我自己本地电脑上的一个程序。这个程序可以让大模型来调用,在本地电脑上执行一些代码,然后把代码执行结果给大模型,并且大模型还能够理解代码的执行结果。

如何实现的思考

AI 大模型的输入和输出都是字符串。在聊天方式下,人脑当然可以阅读理解AI输出的内容。如果我们使用 Delphi 来写程序,如何知道 AI 想要调用哪个函数?如何让 Delphi 程序去执行这个函数?

Delphi 内置的 WebService 框架

WebService 的底层是 SOAP 调用,而 SOAP 调用的底层通讯是 XML 字符串!

尝试

首先,用 Delphi 创建一个 WebService 服务器端程序用于测试。

构造一个 WebService 服务器端程序

我使用 Delphi 创建了一个 WebService 服务器端程序,它输出给客户端调用的接口定义代码:

复制代码
type
  TMyArrayInt = Array Of Integer;

  { Invokable interfaces must derive from IInvokable }
  IIMyTest = interface(IInvokable)
  ['{10981E31-3C5C-4611-BB68-5964025D690F}']

    { Methods of Invokable interface must not use the default }
    { calling convention; stdcall is recommended }
    function Hello(const S: string): string; stdcall;
    procedure HelloWord(const S: string; var MyResult: string); stdcall;
    function TestArray(A: TIntegerSOAPArray ): TIntegerSOAPArray ; stdcall;
    function XPlusY(const X, Y: Integer): Integer; stdcall;
  end;

这里,我们聚焦到 function XPlusY(const X, Y: Integer): Integer; stdcall; 上,它的实现代码是:

复制代码
function TIMyTest.XPlusY(const X, Y: Integer): Integer;
begin
  Result := X + Y;
end;

WebService 验证客户端

同样,使用 Delphi 创建一个标准的 WebService 客户端程序,去调用服务器的 XPlusY 函数,代码如下:

复制代码
procedure TFmMain.Button3Click(Sender: TObject);
var
  Intf: IIMyTest;
  X, Y, Z: Integer;
begin
  Intf := HTTPRIO1 as IIMyTest;

  X := 10;
  Y := 33;
  Z := Intf.XPlusY(X, Y);
  ShowMessage(Z.ToString);
end;

运行服务器端程序和客户端程序,客户端程序上的 Button3 我点它一下,确实收到服务器端的返回,弹出消息框显示43,成功。

获得 Delphi 的 WebService 客户端程序向服务器发起函数调用的通讯内容

因为客户端是使用 HTTPRIO1 这个控件去调用服务器端,因此,我们在 HTTPRIO1.OnBeforeExecute 事件里面写代码拦截,代码如下:

复制代码
procedure TFmMain.HTTPRIO1BeforeExecute(const MethodName: string; SOAPRequest:
    TStream);
var
  S: TStringStream;
  SS: string;
begin
  S := TStringStream.Create;
  try
    SoapRequest.Position := 0;
    S.CopyFrom(SoapRequest);

    S.Position := 0;
    SS := S.ReadString(S.Size);
    Log(SS);
  finally
    S.Free;
  end;
end;

上述代码中,Log 方法的代码如下:

复制代码
procedure TFmMain.Log(const S: string);
begin
  TThread.Synchronize(nil,
      procedure
      begin
        Memo1.Lines.Add(S);
      end
    );
end;

也就是说,把 HTTPRIO1 向服务器发送的函数调用的请求内容,写到 Memo1 里面,让我可以看见。

接下来再次使用这个客户端程序,执行一次对服务器端 XPlusY 函数的调用,HTTPRIO1 发送的内容如下:

复制代码
<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body xmlns:NS1="urn:IMyTestIntf-IIMyTest" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><NS1:XPlusY><X xsi:type="xsd:int">10</X><Y xsi:type="xsd:int">33</Y></NS1:XPlusY></SOAP-ENV:Body></SOAP-ENV:Envelope>

使用 HTTP Post 直接发送这个 XML 的内容给服务器

创建一个新的 Delphi 程序,在里面放三个控件:

  • Button1;
  • Memo1;
  • IdHTTP1
    IdHTTP1 用于向服务器发起 http 访问。对于 SOAP 来说,这里应该发起 http 的 Post 而不是 http 的 Get

把上面我们从 WebService 客户端程序抓到的 XML 保存为文件,文件名:XML_1.txt,然后使用 IdHTTP1 把它 Post 给 WebService 服务器端,代码如下:

复制代码
procedure TFmMain.Button1Click(Sender: TObject);
var
  S, URL: string;
begin
  Memo1.Lines.Clear;
  URL := 'http://localhost:8080/soap/IIMyTest';    
  S := IdHTTP1.Post(URL,'XML_2.txt');  //成功
  Memo1.Lines.Add(S);
end;

运行这个程序,点击 Button1,能够从 Memo1 上看到来自 WebService 服务器的返回。返回数据是:

复制代码
<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:NS1="urn:IMyTestIntf-IIMyTest"><NS1:XPlusYResponse><return xsi:type="xsd:int">43</return></NS1:XPlusYResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>

上面这段 XML 表明,服务器正确执行了 XPlusY 函数,返回了 43 这个正确的结果。

AI 怎么玩?

这里作为测试,我使用了 DeepSeek 的网页版本。我通过聊天的方式,告诉 DeepSeek:

复制代码
你是一个能够理解 SOAP 调用的专家,我给你一个 SOAP 服务器的调用规范,你能够理解并创建客户端调用这个 SOAP 服务器的 XML 代码吗?

AI 回答:

复制代码
当然可以!我是理解 SOAP 协议和 XML 结构的专家,您只需提供 SOAP 服务的调用规范(例如 WSDL 地址、操作名称、命名空间、请求参数等),我就能为您生成对应的客户端调用 XML 代码。请提供详细信息,我会尽力帮您构建正确的 SOAP 请求。

然后我把服务器的 WSDL 在聊天页面里面发送给 AI,WSDL 如下:

复制代码
# 理解并调用 WebService
## 以下是指定的 WebService 服务器端能够提供的服务的 WSDL:

<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://tempuri.org/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:ns1="http://www.borland.com/namespaces/Types" name="IIMyTestservice" targetNamespace="http://tempuri.org/">
<types>
<xs:schema xmlns="http://www.borland.com/namespaces/Types" targetNamespace="http://www.borland.com/namespaces/Types">
<xs:complexType name="TIntegerSOAPArray">
<xs:complexContent>
<xs:restriction base="soapenc:Array">
<sequence xmlns="http://www.w3.org/2001/XMLSchema"/>
<xs:attribute xmlns:n1="http://schemas.xmlsoap.org/wsdl/" ref="soapenc:arrayType" n1:arrayType="xs:int[]"/>
</xs:restriction>
</xs:complexContent>
</xs:complexType>
</xs:schema>
</types>
<message name="Hello0Request">
<part name="S" type="xs:string"/>
</message>
<message name="Hello0Response">
<part name="return" type="xs:string"/>
</message>
<message name="HelloWord1Request">
<part name="S" type="xs:string"/>
<part name="MyResult" type="xs:string"/>
</message>
<message name="HelloWord1Response">
<part name="MyResult" type="xs:string"/>
</message>
<message name="TestArray2Request">
<part name="A" type="ns1:TIntegerSOAPArray"/>
</message>
<message name="TestArray2Response">
<part name="return" type="ns1:TIntegerSOAPArray"/>
</message>
<message name="XPlusY3Request">
<part name="X" type="xs:int"/>
<part name="Y" type="xs:int"/>
</message>
<message name="XPlusY3Response">
<part name="return" type="xs:int"/>
</message>
<portType name="IIMyTest">
<operation name="Hello">
<input message="tns:Hello0Request"/>
<output message="tns:Hello0Response"/>
</operation>
<operation name="HelloWord">
<input message="tns:HelloWord1Request"/>
<output message="tns:HelloWord1Response"/>
</operation>
<operation name="TestArray">
<input message="tns:TestArray2Request"/>
<output message="tns:TestArray2Response"/>
</operation>
<operation name="XPlusY">
<input message="tns:XPlusY3Request"/>
<output message="tns:XPlusY3Response"/>
</operation>
</portType>
<binding name="IIMyTestbinding" type="tns:IIMyTest">
<binding xmlns="http://schemas.xmlsoap.org/wsdl/soap/" style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="Hello">
<operation xmlns="http://schemas.xmlsoap.org/wsdl/soap/" soapAction="urn:IMyTestIntf-IIMyTest#Hello" style="rpc"/>
<input>
<body xmlns="http://schemas.xmlsoap.org/wsdl/soap/" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:IMyTestIntf-IIMyTest"/>
</input>
<output>
<body xmlns="http://schemas.xmlsoap.org/wsdl/soap/" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:IMyTestIntf-IIMyTest"/>
</output>
</operation>
<operation name="HelloWord">
<operation xmlns="http://schemas.xmlsoap.org/wsdl/soap/" soapAction="urn:IMyTestIntf-IIMyTest#HelloWord" style="rpc"/>
<input>
<body xmlns="http://schemas.xmlsoap.org/wsdl/soap/" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:IMyTestIntf-IIMyTest"/>
</input>
<output>
<body xmlns="http://schemas.xmlsoap.org/wsdl/soap/" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:IMyTestIntf-IIMyTest"/>
</output>
</operation>
<operation name="TestArray">
<operation xmlns="http://schemas.xmlsoap.org/wsdl/soap/" soapAction="urn:IMyTestIntf-IIMyTest#TestArray" style="rpc"/>
<input>
<body xmlns="http://schemas.xmlsoap.org/wsdl/soap/" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:IMyTestIntf-IIMyTest"/>
</input>
<output>
<body xmlns="http://schemas.xmlsoap.org/wsdl/soap/" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:IMyTestIntf-IIMyTest"/>
</output>
</operation>
<operation name="XPlusY">
<operation xmlns="http://schemas.xmlsoap.org/wsdl/soap/" soapAction="urn:IMyTestIntf-IIMyTest#XPlusY" style="rpc"/>
<input>
<body xmlns="http://schemas.xmlsoap.org/wsdl/soap/" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:IMyTestIntf-IIMyTest"/>
</input>
<output>
<body xmlns="http://schemas.xmlsoap.org/wsdl/soap/" use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:IMyTestIntf-IIMyTest"/>
</output>
</operation>
</binding>
<service name="IIMyTestservice">
<port name="IIMyTestPort" binding="tns:IIMyTestbinding">
<address xmlns="http://schemas.xmlsoap.org/wsdl/soap/" location="http://localhost:8080/soap/IIMyTest"/>
</port>
</service>
</definitions>

请详细分析上述 WSDL,仔细思考,给出这个 WebService 服务器提供了多少个函数,给出一个函数列表,包括每个函数的参数。

复制代码
AI回答如下:

根据提供的 WSDL 文件分析,该 WebService 服务器提供了 4 个函数,每个函数对应一个操作(operation)。以下是详细的函数列表及参数说明:

1. Hello
描述:简单的问候函数,接收一个字符串并返回一个字符串。

输入参数:

S (string):输入的字符串。

输出参数:

return (string):返回的字符串。

2. HelloWord
描述:接收两个字符串参数,并返回一个字符串(注意:输入参数中包含 MyResult,与输出参数同名,但属于不同的消息部分)。

输入参数:

S (string):第一个输入字符串。

MyResult (string):第二个输入字符串。

输出参数:

MyResult (string):返回的字符串。

3. TestArray
描述:接收一个整数数组,并返回一个整数数组。

输入参数:

A (TIntegerSOAPArray):整数数组,类型为自定义的 SOAP 数组。

输出参数:

return (TIntegerSOAPArray):整数数组。

4. XPlusY
描述:接收两个整数,返回它们的和。

输入参数:

X (int):第一个整数。

Y (int):第二个整数。

输出参数:

return (int):两数之和。

补充说明
所有操作均采用 RPC 编码风格(style="rpc"),并使用 SOAP 1.1 编码(encodingStyle="http://schemas.xmlsoap.org/soap/encoding/")。

服务地址为:http://localhost:8080/soap/IIMyTest(需根据实际部署修改)。

SOAP Action 格式为:urn:IMyTestIntf-IIMyTest#操作名,例如 Hello 的 SOAP Action 为 urn:IMyTestIntf-IIMyTest#Hello。

消息体使用的命名空间为:urn:IMyTestIntf-IIMyTest。

如果需要生成具体的 SOAP 请求 XML 示例,请告知要调用的函数及参数值。

我在网页聊天窗口继续输入:

复制代码
# 调用 XPlusY 函数

现在你需要作为一个 WebService 客户端,调用服务器提供的 XPlusY 函数,你必须生成调用 XPlusY 函数的完整的符合SOAP协议的XML给服务器端。
调用 XPlusY 函数的两个参数分别是:X=12; Y=22;
请深入思考后输出符合规范的XML

AI 输出作为 WebService 客户端调用服务器端函数的 XML 如下:

复制代码
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
               xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <XPlusY xmlns="urn:IMyTestIntf-IIMyTest">
      <X xsi:type="xsd:int">12</X>
      <Y xsi:type="xsd:int">22</Y>
    </XPlusY>
  </soap:Body>
</soap:Envelope>

上述 XML 看起来和 Delphi 的客户端调用服务器端函数的 XML 有点不一样,但主要内容是相同的。我使用这个 XML 能不能成功调用 Delphi 写的 WebService 服务器端程序呢?把上述 XML 保存为 XML_0.TXT 然后用 IdHTTP1 去 POST 给服务器端程序,然后看到成功的返回内容,看起来服务器端正确理解了这个XML并执行了 XPlusY 这个函数。服务器返回的 XML 如下:

复制代码
<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:NS1="urn:IMyTestIntf-IIMyTest"><NS1:XPlusYResponse><return xsi:type="xsd:int">34</return></NS1:XPlusYResponse></SOAP-ENV:Body></SOAP-ENV:Envelope>

那么,我的服务器端程序返回的 XML,AI 能不能正确理解呢?我把服务器返回的 XML 复制粘贴到 AI 的聊天框里面,输出Delphi写的服务器程序的返回值给AI,

AI 的回答是:

从 SOAP 调用的角度来看,服务器返回的 XML 是一个标准的 SOAP 1.1 响应,表明对 XPlusY 函数的调用已成功执行,并返回了计算结果。以下是详细解释:

  1. 响应整体结构
    xml

<?xml version="1.0"?>

<SOAP-ENV:Envelope

xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"

xmlns:xsd="http://www.w3.org/2001/XMLSchema"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">

<SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"

xmlns:NS1="urn:IMyTestIntf-IIMyTest">

NS1:XPlusYResponse

34

</NS1:XPlusYResponse>

</SOAP-ENV:Body>

</SOAP-ENV:Envelope>

  1. 关键元素和属性解释

SOAP-ENV:Envelope:根元素,声明了 SOAP 必需的命名空间:

xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/":SOAP 信封命名空间。

xmlns:xsd 和 xmlns:xsi:XML Schema 命名空间,用于数据类型声明。

xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/":SOAP 编码命名空间,表示使用了 SOAP 1.1 编码规则。

SOAP-ENV:Body:消息体,包含实际的响应内容。

SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/":明确指定了消息体采用 SOAP 编码风格,与 WSDL 中定义的 use="encoded" 一致。

xmlns:NS1="urn:IMyTestIntf-IIMyTest":在 Body 上声明了命名空间前缀 NS1,其值为操作的命名空间 urn:IMyTestIntf-IIMyTest。

NS1:XPlusYResponse:响应元素,命名空间前缀 NS1 指向 urn:IMyTestIntf-IIMyTest,元素名 XPlusYResponse 遵循 RPC 响应的命名惯例(方法名 + "Response")。它包含一个子元素 return。

return:输出参数元素,表示函数的返回值。

xsi:type="xsd:int":通过 xsi:type 显式声明了数据类型为整数(xsd:int),符合 SOAP 编码规范中对数据类型的描述。

元素内容为 34,即计算结果(12 + 22 = 34)。

  1. 与请求的对应关系
    请求中我们发送了 XPlusY 操作,参数 X=12 和 Y=22。

服务器正确处理了请求,计算两数之和,并将结果包装在标准响应结构中返回。

响应中的命名空间和编码风格与请求完全匹配,体现了 RPC/encoded 模式的服务交互。

  1. 结论
    该响应表明:

调用 成功(无 SOAP Fault)。

返回值为 34,验证了 XPlusY 函数的正确性。

服务器遵循了 WSDL 定义的绑定,使用了 RPC/encoded 风格,并正确序列化了返回数据。

因此,您的客户端调用已成功执行,并得到了预期的结果。

结论

经过上述测试,发现 DeepSeek 确实可以在明确要求 SOAP 调用的指示下,自己创建 SOAP 调用的 XML,并且能成功让 WebService 服务器程序执行相关的函数,也能正确理解函数执行的返回结果。

虽然AI和WebService服务器程序的通讯,是我在中间人肉中转的,但验证了 AI 可以调用 WebService 程序。

如果我写一个程序,直接使用 AI 的 API 接口,我的程序就可以自动将 WebService 的 WSDL 发送给 AI,然后自动接收 AI 传过来的 XML,然后我的程序可以把这个 XML 发送给服务器,达到调用服务器的函数或者方法的目的,并且可以把函数调用结果返回给 AI,AI 也能正确理解返回结果,因此 AI 也可以决定接下来可以做什么。这样一来,技术上,我就可以使用 Delphi 来实现一个 AI agent 了。

相关推荐
RichardLau_Cx1 小时前
零依赖!纯前端 AI 辅助病例管理系统 aiCaseManage:无后端也能实现诊疗行为核验
前端·人工智能·前端开发·localstorage·医疗科技·ai辅助开发·零依赖项目
qq_24218863322 小时前
AI内容审核系统(简化版实现)
人工智能·深度学习·目标检测
啊阿狸不会拉杆2 小时前
《计算机视觉:模型、学习和推理》第 9 章-分类模型
人工智能·python·学习·算法·机器学习·计算机视觉·分类
feasibility.2 小时前
用OpenClaw做qq ai办公机器人(支持群聊关键词触发+自定义域名发送任意邮件)
人工智能·科技·阿里云·机器人·agi·qq·openclaw
多恩Stone2 小时前
【3D-AICG 系列-13】Trellis 2 的 SC-VAE 的 Training Loss 细节
人工智能·算法·3d·aigc
njsgcs2 小时前
专业名词写在rag里而不是skill里
人工智能
love530love2 小时前
解决微软登录错误 0xCAA82EE2 & 身份验证故障排查指南
运维·人工智能·microsoft·onedrive·microsoft 365·teams·microsoftonline
Aaron15882 小时前
RFSOC与ADRV9009、AD9026、AD9361技术指标及应用场景对比分析
人工智能·算法·fpga开发·硬件工程·信息与通信·信号处理·基带工程
A小码哥2 小时前
MCP-Atlas:首个大规模 AI 模型工具使用基准测试详解
人工智能