基于 SOC 职业分类
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/tools-only/X-Skills --skill synth-api命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
正在显示 SKILL.md
Index of Build Systems Skills
Coordination patterns for distributed dataflow systems including barriers, epochs, and distributed snapshots
Windowing, sessionization, time-series aggregation, and late data handling for streaming systems
| name | synth-api |
| version | 0.7.15 |
| description | Use the Synth AI SDK end-to-end for policy optimization (GEPA), graph optimization, eval, and inference |
This skill explains how to run Synth end-to-end with:
gepa.optimize() interface)Reference demos have moved to the sibling Benchmarking repo.
SYNTH_API_KEY: your API key (or mint a demo key below)SYNTH_BACKEND_URL (optional): backend base URL, default https://api.usesynth.aiSynth uses three distinct keys. Do not mix them:
| Key | Purpose | Header | When needed |
|---|---|---|---|
SYNTH_API_KEY | Authenticates SDK/CLI calls to the Synth backend | Authorization: Bearer <key> | Always |
ENVIRONMENT_API_KEY | Authenticates backend-to-container requests | x-api-key: <key> | Cloudflare tunnels |
SynthTunnel worker_token | Authenticates tunnel relay to container | Passed as container_worker_token in job config | SynthTunnel (default) |
Common failures:
Invalid API key on /api/jobs/* = wrong key sent to backend.SYNTH_TUNNEL_ERROR: Invalid worker token = wrong tunnel relay token.Demo keys are short-lived (default 4 hours) and are great for notebooks or quick starts.
import os
from synth_ai.core.utils.env import mint_demo_api_key
SYNTH_API_BASE = os.environ.get("SYNTH_BACKEND_URL", "https://api.usesynth.ai")
SYNTH_API_KEY = os.environ.get("SYNTH_API_KEY") or mint_demo_api_key(SYNTH_API_BASE)
os.environ["SYNTH_API_KEY"] = SYNTH_API_KEY
Only needed when using Cloudflare tunnels. SynthTunnel handles auth automatically.
import os
from synth_ai.sdk.container.auth import mint_environment_api_key, setup_environment_api_key
SYNTH_API_BASE = os.environ.get("SYNTH_BACKEND_URL", "https://api.usesynth.ai")
SYNTH_API_KEY = os.environ["SYNTH_API_KEY"]
ENVIRONMENT_API_KEY = mint_environment_api_key()
os.environ["ENVIRONMENT_API_KEY"] = ENVIRONMENT_API_KEY
setup_environment_api_key(SYNTH_API_BASE, SYNTH_API_KEY, token=ENVIRONMENT_API_KEY)
/rollout + /task_info.import synth_ai
print(synth_ai.__version__) # "0.7.15"
Minimum container shape:
provide_taskset_description()provide_task_instances(seeds)rollout(request) -> RolloutResponsefrom synth_ai import ContainerConfig, create_container
from synth_ai.sdk.container._impl.contracts import (
RolloutMetrics, RolloutRequest, RolloutResponse, TaskInfo,
)
def create_banking77_container(system_prompt: str):
async def run_rollout(request: RolloutRequest, fastapi_request) -> RolloutResponse:
reward = 1.0 # Your task logic here; return reward in [0, 1]
return RolloutResponse(
trace_correlation_id=request.trace_correlation_id,
reward_info=RolloutMetrics(outcome_reward=reward),
trace=None,
)
def provide_taskset_description():
return {"splits": ["train", "test"], "sizes": {"train": 1000, "test": 1000}}
def provide_task_instances(seeds):
for seed in seeds:
yield TaskInfo(
task={"id": "banking77", "name": "Banking77 Intent Classification"},
dataset={"id": "banking77", "split": "train", "index": seed},
inference={"tool": "banking77_classify"},
limits={: },
task_metadata={: seed},
)
create_container(
ContainerConfig(
app_id=,
name=,
description=,
provide_taskset_description=provide_taskset_description,
provide_task_instances=provide_task_instances,
rollout=run_rollout,
cors_origins=[],
)
)
Relay-based tunnel — no external binary required, supports 128 concurrent requests:
from synth_ai.core.tunnels import TunneledContainer
app = create_banking77_container("baseline prompt")
tunnel = await TunneledContainer.create_for_app(
app=app,
local_port=None, # auto-select
api_key=os.environ["SYNTH_API_KEY"],
)
CONTAINER_URL = tunnel.url # https://st.usesynth.ai/s/rt_...
WORKER_TOKEN = tunnel.worker_token # pass to job config
print("Container URL:", CONTAINER_URL)
Requires cloudflared installed (brew install cloudflared):
from synth_ai.core.tunnels import TunneledContainer, TunnelBackend
app = create_banking77_container("baseline prompt")
tunnel = await TunneledContainer.create_for_app(
app=app,
local_port=None,
backend=TunnelBackend.CloudflareQuickTunnel,
)
CONTAINER_URL = tunnel.url # https://....trycloudflare.com
When using Cloudflare tunnels, pass container_api_key instead of container_worker_token in job configs.
GEPA mutates prompt candidates and evaluates them via rollouts. Use a config dict or a TOML file.
import os
from synth_ai import PolicyOptimizationJob
config_body = {
"policy_optimization": {
"algorithm": "gepa",
"container_url": CONTAINER_URL,
"env_name": "banking77",
"initial_prompt": {
"messages": [
{"role": "system", "order": 0, "pattern": "Baseline system prompt"},
{"role": "user", "order": 1, "pattern": "Customer Query: {query}\n\nAvailable Intents:\n{available_intents}"},
],
"wildcards": {"query": "REQUIRED", "available_intents": "OPTIONAL"},
},
"policy": {
"model": "gpt-4.1-nano",
"provider": "openai",
"inference_mode": "synth_hosted",
"temperature": 0.0,
"max_completion_tokens": 256,
},
"gepa": {
"env_name": "banking77",
"evaluation": {
"seeds": list(range(50)),
: ((, )),
},
: {: , : , : },
: {: },
: {: , : , : },
: {: , : },
},
},
}
job = PolicyOptimizationJob.from_dict(
config_dict=config_body,
container_worker_token=WORKER_TOKEN,
skip_health_check=,
)
job_id = job.submit()
result = job.stream_until_complete(timeout=)
()
from synth_ai import PolicyOptimizationJob
job = PolicyOptimizationJob.from_config(
config_path="gepa_config.toml",
container_worker_token=WORKER_TOKEN,
)
job.submit()
result = job.stream_until_complete(timeout=3600.0)
For a simpler interface that handles container + tunnel setup automatically:
from synth_ai import gepa
trainset, valset, _ = gepa.examples.banking77.init_dataset()
result = gepa.optimize(
seed_candidate={"system_prompt": "You are a helpful assistant."},
trainset=trainset,
valset=valset,
task_lm="openai/gpt-4.1-mini",
max_metric_calls=150,
reflection_lm="openai/gpt-5",
)
print(result.best_candidate["system_prompt"])
Key parameters:
seed_candidate: dict with a system_prompt (or instruction/prompt) keytrainset / valset: lists of dicts with input and answer keystask_lm: "provider/model" stringreflection_lm: model for GEPA proposer (controls proposer effort)max_metric_calls: budget capCombines container + tunnel + lifecycle in a single async context manager:
from synth_ai import InProcessContainer, PolicyOptimizationJob
async with InProcessContainer(
app=create_banking77_container("baseline prompt"),
port=8114,
tunnel_mode="synthtunnel", # default; also "quick", "local", "preconfigured"
api_key=os.environ["SYNTH_API_KEY"],
) as container:
print(f"Running at: {container.url}")
job = PolicyOptimizationJob.from_dict(
config_dict=config_body,
container_worker_token=container.worker_token,
)
job.submit()
result = job.stream_until_complete(timeout=3600.0)
Train a verifier graph with an RLM backbone:
from synth_ai import GraphOptimizationJob
job = GraphOptimizationJob.from_dataset(
dataset="verifier_dataset.json",
graph_type="rlm",
policy_models=["gpt-4.1"],
proposer_effort="medium",
rollout_budget=200,
)
job.submit()
result = job.stream_until_complete(timeout=3600.0)
Eval jobs score a fixed set of held-out seeds for a final report.
import os
from synth_ai import EvalJob, EvalJobConfig
config = EvalJobConfig(
container_url=CONTAINER_URL,
backend_url=os.environ.get("SYNTH_BACKEND_URL", "https://api.usesynth.ai"),
api_key=os.environ["SYNTH_API_KEY"],
container_worker_token=WORKER_TOKEN, # for SynthTunnel
env_name="banking77",
seeds=list(range(100, 150)),
policy_config={"model": "gpt-4.1-nano", "provider": "openai"},
env_config={"split": "test"},
concurrency=10,
)
job = EvalJob(config)
job.submit()
result = job.poll_until_complete(timeout=600.0, interval=2.0, progress=True)
print(f"Mean reward: {result.mean_reward}")
Run a built-in verifier graph with rubric criteria passed at runtime:
import os
from synth_ai import VerifierClient
client = VerifierClient(
base_url=os.environ.get("SYNTH_BACKEND_URL", "https://api.usesynth.ai"),
api_key=os.environ["SYNTH_API_KEY"],
)
result = await client.evaluate(
job_id="zero_shot_verifier_single",
trace={"session_id": "s", "session_time_steps": []},
rubric={
"event": [{"id": "accuracy", "weight": 1.0, "description": "Correctness"}],
"outcome": [{"id": "task_completion", "weight": 1.0, "description": "Completed task"}],
},
options={"event": True, "outcome": True, "model": "gpt-5-nano"},
policy_name="my_policy",
container_id="my_task",
)
# Install
pip install synth-ai==0.7.15
# or: uv add synth-ai
# Check version
synth-ai --version
# List packaged OpenCode skills
synth-ai skill list
# Install a skill to a custom directory
synth-ai skill install synth-api --dir ~/custom/opencode/skill
# Serve a container locally
synth-ai container serve my_module:app --port 8114
# Deploy a container to Synth Harbor
synth-ai container deploy --name my-app --app my_module:app --dockerfile ./Dockerfile --context . --wait
import os
import requests
base = os.environ.get("SYNTH_BACKEND_URL", "https://api.usesynth.ai")
resp = requests.get(
f"{base}/api/health",
headers={"Authorization": f"Bearer {os.environ['SYNTH_API_KEY']}"},
timeout=30,
)
resp.raise_for_status()
print(resp.json())
Modules follow the API Stability Lifecycle:
| Module | Status | Import |
|---|---|---|
PolicyOptimizationJob | Stable | from synth_ai import PolicyOptimizationJob |
GraphOptimizationJob | Stable | from synth_ai import GraphOptimizationJob |
EvalJob | Stable | from synth_ai import EvalJob |
ContainerConfig | Stable | from synth_ai import ContainerConfig |
create_container | Stable | from synth_ai import create_container |
InProcessContainer | Stable | from synth_ai import InProcessContainer |
TunneledContainer | Stable | from synth_ai.core.tunnels import TunneledContainer |
VerifierClient | Beta | from synth_ai import VerifierClient |
GraphCompletionsClient | Beta | from synth_ai import GraphCompletionsClient |
InferenceClient | Beta | from synth_ai import InferenceClient |
gepa.optimize | Beta | from synth_ai.gepa import optimize |
dspy.GEPA | Beta | from synth_ai.dspy import GEPA |
EnvironmentPoolsClient | Alpha | from synth_ai.sdk.environment_pools import EnvironmentPoolsClient |
ManagedPools | Alpha | from synth_ai.sdk.managed_pools import ... |
Legacy aliases (PromptLearningJob, GraphEvolveJob, TunneledContainer, ContainerConfig, create_container, synth_ai.sdk.container.*) still work but are deprecated.
st.usesynth.ai URL. Pass tunnel.worker_token to job configs.trycloudflare.com URL. Requires cloudflared binary.https://api.usesynth.ai/api/inference/v1.SYNTH_API_KEY is set and valid. Do not confuse it with ENVIRONMENT_API_KEY or worker_token./task_info and /rollout return valid RolloutResponse.stream_until_complete() disconnects, it auto-reconnects via SSE. Check backend logs for job status.PromptLearningJob, update to PolicyOptimizationJob. If you see prompt_learning config keys, update to policy_optimization. If you see synth_ai.sdk.container, update to synth_ai.sdk.container.