使用DSPy优化Terraform Agent:先构建验证器,再优化器
Terraform代理会自动生成架构。首先构建一个确定性的验证器,为该代理设定基准,然后使用DSPy和GEPA优化其技能文件,从而获得准确的结果。
编写基础设施代码的智能体很可能曾在某个时候生成过类似这样的模块:它看起来完全合理,读起来就像所有经过审核者认可的模块,但却会因为一些肉眼无法察觉的原因而无法通过 terraform validate 检查。
这一点也有相关衡量标准。IaC-Eval 是一个包含458个精心挑选的Terraform场景的基准测试,据称GPT-4在该测试中的通过率仅为19.36%,而同一模型在更严格的Python基准测试中的通过率则为86.6%。另一项关于智能体驱动的IaC生成的研究显示,Qwen2.5-Coder 7B的通过率为14.0%,GPT-4o为41.4%,GPT-5.4则为62.4%。
为什么基础设施代码比 Python 难得多?一个正确的配置必须同时满足四项要求:有效的语法、与所使用版本的模式相匹配、结构完整的依赖关系图,以及符合组织自身的政策。缺少任何一项都会导致整个配置出错。即便 Python 的配置只有 90% 正确,它通常仍能运行,而 Terraform 即使只有 90% 正确也无法正常工作。
这项研究还得出了些让常规解决方案显得不可靠的结果。少样本提示、思维链机制以及多轮交互都只能起到很小的作用。实际上,约 79% 的政策执行失败源于提示中信息缺失,而非模型能力不足。模型的能力其实足够,只是没有获得正确的信息而已。
这是个优化问题。因此,这里的计划是使用现有的 Terraform 代理,构建用于判断其是否有所改进的评估机制,然后针对该评估结果运行完整的 DSPy 工作流程:编写程序、进行评估、实施优化。所有步骤都是可运行的。配套项目被分为三个文件夹,每个阶段对应一个文件夹:
agent/ the deepagents Terraform agent, its tools, prompts, and skills
eval/ the verifier, 38 tasks with Rego policies, and the benchmark
optimizer/ the DSPy program, metric, and GEPA compile
起始代理
这部分内容宜简短,因为它并非重点,任何代理都可以替代。该代理会查询真实的架构,编写需经过检查的文件,并在回复前进行验证。
agent/tools.py 中包含了三个工具。代理在编写文件之前会先读取真实的提供者架构。它所编写的文件在生成过程中会进行格式化与语法检查,随后会对整个配置进行验证,修复编译器指出的问题,只有完成这些步骤后才回复。
它基于 LangChain 的代理框架 deepagents 构建,该框架用于实现具备工具和技能的代理,但实际上该框架的作用并不大,关键在于其结构设计:
from deepagents import create_deep_agent
agent = create_deep_agent(
model="openrouter:openai/gpt-5.6-luna",
tools=[provider_schema, write_terraform, validate_config],
system_prompt=SYSTEM_PROMPT,
skills=["./agent/skills"], # SKILL.md — the thing we'll optimize
)
技能目录值得仔细研究,因为这里的其他所有内容都在为其优化。技能实际上是一份 Markdown 格式的指令文件,智能体会在系统提示词旁边加载它,这种被称为 Agent Skills 的格式正迅速普及:Claude、GitHub Copilot 和 deepagents 都采用相同的 SKILL.md 结构。它将不同功能清晰地分开。系统提示词仅负责处理基础逻辑(如如何调用工具、如何格式化输出),而技能则包含领域知识,比如 Terraform 的规范、安全默认设置以及各提供方的特殊特性。由于同一份文件可在多个智能体上使用,技能还具有可移植性。
大多数关于DSPy的描述都会引导优化器关注程序的主入口。但这里要测试的问题有所不同:它能否优化某个技能模块?实际团队会将大部分手动调优工作集中在这些技能模块上,因为它们承载着专业知识,且会在评审过程中不断被修改。而在这个项目中,该技能模块是手写的,存储在git中,会像其他文件一样经过代码审查。更关键的是,它从未被测量过,这才是真正的问题所在,而DSPy正是为了解决这一问题而设计的,因为对该文件的任何修改都可能改变实际运行行为,却没有任何测试作为保障。
失败的实际表现
让我们从修复之前的真实输出结果开始看。这些结果产生于记录的基准测试运行中,当时智能体没有可用工具,只能直接将HCL代码写入回复中。请求内容是要求使用客户管理的加密方式来创建状态桶:
encryption {
kms_key_name = var.encryption_key_name
}
lifecycle_rules {
...
看起来没问题,但用验证工具检测后结果却不同:
$ tofu validate
Error: Missing required argument
on main.tf line 18, in resource "google_storage_bucket" "terraform_state":
The argument "default_kms_key_name" is required, but no definition was found.
Error: Unsupported argument
on main.tf line 19, in resource "google_storage_bucket" "terraform_state":
An argument named "kms_key_name" is not expected here.
Error: Unsupported block type
on main.tf line 22, in resource "google_storage_bucket" "terraform_state":
Blocks of type "lifecycle_rules" are not expected here. Did you mean
"lifecycle_rule"?
同一个资源出现了三个错误。所需参数应为default_kms_key_name,而kms_key_name属于其他Google资源,正因如此才会显得合理。此外,某个块名称也被误改为并不存在的形式。
将基础故障按类型分类后,发现80%的验证错误属于虚构的架构:这些参数、块或属性看似真实的HCL格式,但实际上并不存在于相关资源中。google提供程序拥有大约一千种资源类型,且每次更新都会发生变化,因此该模型只是凭记忆调用特定版本的API,而记忆难免会产生看似合理的虚构内容。
这三种工具直接针对该诊断问题。单独使用它们就能为测试成绩增加27.7分(使用下面介绍的这套工具后,通过率从41.7%上升到了69.4%)。由于write_terraform会自动执行fmt命令,而非依赖模型来处理空白字符,格式错误降为零。由于代理现在能够看到编译器所看到的内容,架构错误也降为零。剩下的问题几乎都与意图相关,即代理是否构建了用户要求的功能,而这正是DSPy发挥作用的地方。
以下是使用当前具备工具功能的代理来执行同一任务的过程:
$ uv run python -m agent.run --task eval/tasks/backend-var-interpolation.json
task backend-var-interpolation (opentofu)
model openai/gpt-5.6-luna engine=deepagents
files main.tf, variables.tf
tools {'write_terraform': 2, 'validate_config': 1, 'validate_pass': 1}
elapsed 56602ms
共有两次写入操作和一次验证,只有当编译器确认无误后,代理才会作出响应。任务文件以及 opentofu 目标均来自评估套件,后续工作也将从那里继续。
框架之前的评分器
要判断这些措施是否有用,就需要用比主观感觉更确切的标准来回答“输出质量如何?”。大多数领域都使用大型语言模型作为评分器,通过让不同模型的观点相互对比且没有真实标准,而评分器本身也需要进一步验证。
Terraform没有这个问题,因为已经在持续集成环境中运行的工具链本身就是评分器:
tofu fmt -check可以检测格式问题。tofu validate能发现语法、架构和引用错误。tflint会标记已废弃的参数和无效的机器类型。
tofu test结合mock_provider可在无需任何云服务凭证的情况下检查语义正确性。conftest结合OPA Rego可验证意图,即检查代理是否按需求构建了相应内容。这五个确定性检查机制均实现在eval/verifier/run.py中。整个过程不涉及任何评判机制,API调用也不会产生任何费用,而且由于该项目刻意未包含任何apply操作,因此没有任何步骤会生成需付费的资源。
尽管最后一个检查最为重要,但大多数人都会跳过它。validate仅能说明配置可以编译通过,而Rego则能确认存储桶确实已开启加密功能——这正是需求所规定的,也使得配置不仅是有效而已,更是正确无误的:
package main
import rego.v1
deny contains "bucket must use a customer-managed KMS key" if {
some name
bucket := input.resource.google_storage_bucket[name][_]
not bucket.encryption
}
那些已经通过 OPA 实施策略的团队,很可能在 Terraform Cloud 或其 CI 流水线中也有许多类似的策略,这些策略可以直接复用而无需修改。这是一种“左移”策略,应用于各个代理节点。虽然 Terraform Cloud 会在应用时拒绝有问题的方案,但那时代码早已存在,审核人员也已阅读过代码,且运行任务早已排队。在生成代码时运行相同的 Rego 规则,便能在耗费大量精力之前发现违规问题。
测试测试工具本身。 这是最值得借鉴的步骤。允许一切通过的策略其实比没有策略更糟糕,因为它会给每个代理版本相同的评分,并默默报告“无变化”。因此,eval/tasks/policy/ 目录中的每个策略都会附带一个合规的测试用例和一个出错的测试用例,同时还有一个脚本会从两个方向进行验证:
$ cd eval/tasks && ./check_policies.sh
...
✓ vpc-subnet-firewall good=0 bad=2
✅ 38/38 policies verified in both directions
共有38项任务以这种方式编写。它们涉及安全默认设置、资源间的连接方式、不同提供商架构的兼容性、目标方言选择、限制条件(代理是否会添加用户不需要的内容)以及文件结构。每项任务都会将相应的提示与能够体现其意图的Rego策略配对。对于目标方言有特殊处理:每项任务都会明确说明其针对的是terraform还是opentofu,因为这两者已出现差异(OpenTofu支持状态加密和提供商的for_each功能,而Terraform则提供Stacks功能),因此如果代理错误地选择了其中一种,就会无法通过验证。
那幅关于五个门的图还标出了智能体无法跨越的检测边界,但人们很容易高估这一边界的重要性。在实际应用中,智能体应当配备OPA工具,在响应之前先检查相关策略。这同样是“左移”策略的体现,能够帮助生成更优质的代码。
边界的作用有所不同。在这里,同样的策略被用作衡量标准,用于比较不同的技能、模型以及优化器的运行结果。如果智能体能够针对用于评估实验的策略本身进行迭代,那么所有变体都会趋向于通过评估,此时比较就失去了意义。这就是应用于工具领域的保留测试集原则。其规则是:智能体可以查看除当前用于评估实验的策略之外的任何检查项。如果该智能体将随策略工具一同部署,那么也需要对这种配置进行评估,使用保留的策略进行评分,或统计所需的修复迭代次数,而非判断其是否通过。
采用 DSPy
DSPy将自己定位为用于编程语言模型而非仅用于提示它们的框架。其文档将工作流程分为三个阶段:编程、评估和优化,这一顺序本身就蕴含着重要意义:优化器是最后处理的环节,而在此之前的所有步骤决定了优化器的可靠性。优化器恰好需要三样东西:程序、评估指标以及数据。
DSPy的所有功能都位于optimizer/目录下,其设置则依赖于uv工具:
uv add dspy
uv sync
第一阶段:编程
签名是一种针对单次LM调用的类型化契约,包含输入、输出以及描述该任务的文档字符串。该签名位于optimizer/harness.py中:
import dspy
class AuthorConfiguration(dspy.Signature):
"""Write a complete, valid Infrastructure-as-Code configuration."""
request: str = dspy.InputField(
desc="What the user wants built, in natural language."
)
target: str = dspy.InputField(
desc="Which dialect to target: 'terraform' or 'opentofu'. These have "
"diverged — code targeting the wrong one will fail validation."
)
config: str = dspy.OutputField(
desc="The complete configuration as fenced HCL blocks. Start each block "
"with a comment naming its file, e.g. '# main.tf'."
)
正是这些省略之处才关键所在。文中没有“你是一名资深的 Terraform 工程师”之类的表述,也没有实例演示,更不会纠结格式问题。字段名称和描述本身就承载着含义,而优化器会负责语句的表达。
任何认为这很神奇的人,只需一句话就能打破这种错觉:
dspy.inspect_history(n=1)
它会打印出适配器根据签名生成的实际提示语。该功能的实际输出如下所示:
System message:
Your input fields are:
1. `request` (str): What the user wants built, in natural language.
2. `target` (str): Which dialect to target: 'terraform' or 'opentofu'. ...
Your output fields are:
1. `config` (str): The complete configuration as fenced HCL blocks. ...
[[ ## request ## ]]
{request}
[[ ## target ## ]]
{target}
[[ ## config ## ]]
{config}
In adhering to this structure, your objective is:
Write a complete, valid Infrastructure-as-Code configuration ...
没有什么是隐藏的。它是由签名生成的结构性模板,这正是优化器能够安全地重写它的原因,也是当行为出现异常时首先需要检查的地方。
模块会将某种技术应用于签名,而两者是独立变化的。同一个签名既可以作为单次执行的任务,先进行推理,也可以作为工具循环的驱动部分:
generate = dspy.Predict(AuthorConfiguration) # one shot
generate = dspy.ChainOfThought(AuthorConfiguration) # reason first
generate = dspy.ReAct(AuthorConfiguration, tools=[...]) # run a tool loop
该智能体使用了工具,因此它与 dspy.ReAct 相关联,并被赋予了与实际部署的智能体所调用的完全相同的工具函数,这些函数直接从智能体包中导入。相关代码位于 optimizer/harness_deepagents.py 中:
from agent.tools import make_tools # the deployed agent's tools
class TerraformAuthoringAgent(dspy.Module):
def __init__(self, seed_instruction: str):
super().__init__()
# Seed the SIGNATURE before constructing ReAct, so DSPy appends its
# tool protocol to your instruction instead of replacing it.
seeded = AuthorConfiguration.with_instructions(seed_instruction)
lc_tools = make_tools(work_dir, binary="terraform", stats={})
self.react = dspy.ReAct(
seeded,
tools=[dspy.Tool(t.func, name=t.name, desc=t.description)
for t in lc_tools.values()],
max_iters=10,
)
def forward(self, request: str, target: str = "terraform"):
return self.react(request=request, target=target)
该设计中最关键的决定是:优化即将被部署的同一程序。早期的一次实验优化了一个一次性生成器,然后将输出结果传递给一个使用工具的智能体,但由于指令是为那些实际智能体已不再产生的错误情况而调整的,导致所有数值都失去了意义。
初始指令即为现有的 SKILL.md,因此无法重新开始,真正的问题在于手写的文本是否能够得到改进。DSPy 并不知道该字符串属于技能而非主提示,因为它只看到签名中的指令文本。正因如此,技能实验才具备可行性:实验结果会直接以 SKILL.md 的形式保存下来,适用于任何能够读取技能的智能体。
第二阶段:评估
DSPy中的数据类型为dspy.Example,这是一种能够识别哪些字段为输入的字典。optimizer/dataset.py中的加载器会直接转换该数据结构:
dataset = [
dspy.Example(
task_id=t["id"],
request=t["prompt"],
target=t["target"],
rego=t["rego"], # path to this task's policy
).with_inputs("request", "target")
for t in tasks
]
未被标记为输入字段的内容会作为元数据一同传输。该机制使用rego来查找匹配的策略,而模型根本无法看到这些内容。
挑选示例的方式值得详细说明,因为数据集决定了优化器能够学习的一切内容。这些示例并非从基准测试中抓取的,而是模仿了真实工单的写法,例如请求使用客户管理的密钥对GCS状态存储桶进行加密,或是允许某个服务账户访问某个存储桶而无法访问其他内容。这些示例涵盖了平台团队需要处理的核心资源:存储、网络、IAM、SQL和Pub/Sub,同时还包括针对已出现故障模式的测试类型:那些需要模型自行设计参数的复杂结构资源、用于确保智能体不会添加未经请求的资源的约束任务,以及上述的方言处理任务。其中有一些示例被刻意设置得较为困难,因为如果一套系统从一开始就能通过所有测试,就无法体现其改进空间。
38个示例听起来数量不多,确实如此。重点在于确保每个示例都能被充分覆盖,因为它们各自有不同的策略,同时需要做到公平分配。在优化之前先进行数据分割,并将测试集视为神圣不可侵犯:训练集是优化器学习的数据,验证集用于筛选候选方案,而测试集则只在最后进行一次评分。大多数提示工程实践都会忽略这一规范,正是由于忽视了它,人们才会误以为某些改动确实有效,而实际上并非如此。在这个项目中就发生过两次这样的情况,每次都是在较小的验证样本上取得成功,但一旦样本规模扩大,结果就变了。
metric模块是验证工具所依赖的部分,它实际上是一个承担三项功能的函数(optimizer/metric.py):
def verify_metric(example, prediction, trace=None, pred_name=None, pred_trace=None):
"""Score with the SAME verifier that produces our benchmark numbers."""
result = verify(
config_dir=materialise(prediction.config),
policy_dir=example.rego,
target=example.target,
)
# Job 1 — bootstrapping (trace is set): a strict bool. Only outputs that
# FULLY pass may become worked examples.
if trace is not None:
return result.passed
# Job 2 — reflective optimization (pred_name is set): score AND feedback.
# GEPA reads the text to understand *why* a candidate failed.
if pred_name is not None:
return dspy.Prediction(score=result.score, feedback=format_failures(result))
# Job 3 — plain evaluation: a float.
return result.score
要保持简洁。如果该指标重新实现了某种评分逻辑,那么被优化的数据与最终输出的数据就会产生偏差,从而导致无法进行有效测量。
在反馈机制方面,这一领域表现尤为突出。反思型优化器会利用用于说明故障的文本,而这里的文本是自由且准确的:即真正的编译错误和真正的策略拒绝情况,就像之前展示的那样。而那些依赖大型语言模型进行判断的字段,则需要为每次评估付费,得到的反馈质量也会差很多,同时还必须对模型判断的结果进行验证。
在采取其他任何措施之前,应先使用 dspy.Evaluate 来测量基准值:
evaluate = dspy.Evaluate(devset=valset, metric=verify_metric,
num_threads=8, display_table=True)
evaluate(program)
3个示例的测试输出如下,而完整测试则需要更长时间:
Average Metric: 0.59 / 3 (19.6%): 100%|██████████| 3/3 [01:16<00:00, 25.60s/it]
INFO dspy.evaluate.evaluate: Average Metric: 0.5882 / 3 (19.6%)
WARNING dspy.evaluate.evaluate: Skipping table display since `pandas` is not installed.
从那段代码中可以得出两个教训。每个“示例”都是一个完整的智能体执行过程,而非单次API调用,因此需相应调整预算。此外,display_table功能需要pandas支持,因此为每个示例对应的表格请安装该库。
如果能养成一个习惯的话,那就是在没有基准值的情况下绝不进行优化。只有这个基准数值才能让优化器的输出具有实际意义。
第三阶段:优化
不同的优化器会调整不同的参数:
BootstrapFewShot用于合成已验证的示例(演示)。MIPROv2通过贝叶斯搜索来调整指令和演示内容。GEPA则通过分析失败轨迹来优化指令。
对于受模式约束的代码而言,指令微调是更有效的解决方案,因为相关代理式IaC研究显示其效果优于注入演示数据的方法,毕竟演示数据无法解决模式幻觉问题。因此,GEPA才是最佳选择,其实现来自optimizer/compile.py:
gepa = dspy.GEPA(
metric=verify_metric,
max_metric_calls=150,
reflection_lm=dspy.LM("openrouter/openai/gpt-5.6-luna", max_tokens=16000),
num_threads=8,
track_stats=True,
)
compiled = gepa.compile(student=program, trainset=trainset, valset=valset)
compiled.save("compiled_state.json", save_program=False)
这两种模型承担不同的任务。任务模型负责生成Terraform代码并最终输出结果;而反思模型则用于分析失败案例并起草候选指令。它的运行次数约为任务模型的40次,后者则需运行约900次,因此在任务模型上投入更多资源是可行的。
一些经过实践总结的重要注意事项:
- 需设置
num_threads参数。有一次忘记设置该参数,导致编译耗时69分钟;事后检测发现机器有94%的时间处于空闲状态,只是在等待接连发出的API调用。 - “150次度量调用”指的是150个代理任务周期,通过工具循环处理后大约相当于900次语言模型调用。
save() 函数。当设置 save_program=False 时,输出为纯 JSON 格式,其中包含优化后的指令文本以及任何自带的演示内容。同样的 JSON 格式也可用于完全脱离 DSPy,因为大约二十行代码(位于 optimizer/to_skill_md.py 中)会将其重新转换成智能体可使用的 SKILL.md 文件。在运行时,根本不会导入 DSPy。 优化器仅作为构建步骤存在,其生成的结果会以差分形式出现在拉取请求中,供人查看并拒绝。GEPA也能从实际运行中学习。在性能较弱的模型中,该智能体不断中断其工具循环:执行一次provider_schema调用后便停止工作,不会留下任何输出。GEPA并未被告知这一情况。它通过分析故障日志,将这一经验融入优化后的指令中:不能仅因为文件已被写入就认为任务完成,因为成功的写入仅能证明HCL语法可解析,还需通过validate_config来检测provider-schema错误及无效引用。这正是通过对实际执行日志的反思,得出的指导,而若靠人工调试的话,需要数小时才能总结出此类经验。
优化后工作流程仍持续见效
同一套系统中的另外两个组件则重新利用了已存在的度量标准。
该度量标准也可在推理时运行。DSPy的BestOfN和Refine功能可以封装任意模块,将其运行N次,然后返回奖励值首次达到阈值的结果:
robust = dspy.Refine(module=program, N=3, reward_fn=verify_metric, threshold=1.0)
这种模式应该很熟悉,因为代理的“验证与修复”循环采用了与编译器中将奖励函数作为依据的相同思路。有证据表明这是最有效的手段:在IaC研究中,通过验证器反馈进行迭代修复,使Qwen 7B的准确率从14.0%提升到了62.9%,优于所有尝试过的提示技术。无论以何种形式,都应在运行时为模型提供相应的验证器。
模型替换现在只需一行代码即可完成,而且还能被量化衡量:
program.set_lm(dspy.LM("openrouter/qwen/qwen3-coder-30b-a3b-instruct"))
evaluate(program)
这比预期更重要。在项目进行到一半时更换为更便宜的模型,导致质量从83.3%下降到37.5%,几乎有一半的运行会放弃工具循环,根本不会生成任何文件。在手动工作流程中根本无法发现这一问题,首个迹象往往来自客户。运行12分钟的评估套件才暴露了这个问题。
真实结果
对于这个智能体而言,编译后的指令并未比手写的指令表现更好。
在两种智能体实现和两种模型上共进行了九次对比测试,其中包括一个保留的测试集,两种模型的得分均为92.9%。该数值对应的是性能更强的模型,而之前提到的41.7%到69.4%的数值则是同一套测试中更便宜的模型所取得的成绩。有两次看似明显的胜出结果被记录下来,但在更大规模的样本测试中结果却发生了反转。
这是最宝贵的经验,也并不说明DSPy存在缺陷。可能存在某种具体且合理的理由解释为何该方法不适用。GEPA所展示的优化效果源自模块化工作流,即每个步骤都使用不同提示词的流程,因此优化器可以将失败归咎于某个模块并对其进行修复。而智能体在每一步都只使用同一个提示词。本杰明·安德森的批评认为,这恰恰消除了GEPA所依赖的局部性特征。
以下是实用建议:
- 对于线性流程,已公布的优化效果很可能同样适用。
- 对于智能体循环流程,在认定其效果之前,应先自行进行测试。
- 无论哪种情况,都应将验证器的反馈直接传递给智能体本身;因为已有相关研究成果及数据作为最有力的支撑。
而这样的测试是可行的,因为相应的测试套件已经存在。
目前的状况
语言模型认为基础设施即代码是一项难题。GPT-4在IaC-Eval测试中仅获得19.36%的分数,这并非靠乐观想法就能解决的提示词问题,常见的技巧也几乎起不到作用。不过,大多数策略失败源于信息缺失而非能力不足,因此仍有提升空间,而这种空间存在于指令和工具中,而非模型权重里。
经实践验证有效的工作流程正是DSPy官方文档所按顺序介绍的那样。在编程方面:需定义合约的签名、创建与实际部署内容对应的模块,以及在不确定发送内容时使用inspect_history功能。在评估方面:需要带有明确输入的示例、可作为优化器反馈的简易指标、任何更改前的基准值,以及仅测试一次的测试集。至于优化阶段,则在相同指标的指导下,保存文本以便在拉取请求中进行审查。
尽管优化器无法超越手工编写的技能,但使用DSPy迫使人们将“正确”的定义以可执行代码的形式写下来。这一机制持续发挥着作用:它在模型更换后检测到46分的性能下降,发现该技能仅有25%的时间被加载(通过重写一句话解决了这个问题,此后加载率达到了100%),还两次阻止了将错误结果误判为胜利的情况。
其实这些功能并不一定非得依赖DSPy,这里的验证工具也并未导入任何DSPy相关组件。DSPy的价值在于强制要求某种度量标准的存在并得以重复使用,从而使一个定义能够驱动回归测试、模型对比、推理时的重试操作以及优化器的工作。那些已有相应规范的团队可能不需要这个框架,而缺乏规范的团队则可以从它那里获得帮助。无论如何,都应停止发布那些无法被量化的提示词修改版本。
相关阅读
- 控制 Bedrock Agent 的行为:提示词阶段、解析器与推理 — 介绍如何通过 Terraform、解析器 Lambda、JSON 规范以及各阶段的推理设置来覆盖 Bedrock 的预处理、调度和后处理提示词。
- 本体结构与模型规模:图结构设计对 AI Agent 的影响 — 探讨同一个保险知识图的三种无损结构如何改变 Azure Cosmos DB 上小型与大型模型的准确率、工具调用次数、token 数量及成本。