同一モデル設定を共有するデプロイ構成(compose.yml)
order-service と menu-service は、いずれも同じ環境変数名のモデル設定を受け取ります。
# food-delivery-demo/compose.yml(抜粋)
order-service:
environment:
ARACHNE_STRANDS_MODEL_ID: ${ARACHNE_STRANDS_MODEL_ID:-}
ARACHNE_STRANDS_MODEL_REGION: ${ARACHNE_STRANDS_MODEL_REGION:-}
menu-service:
environment:
ARACHNE_STRANDS_MODEL_PROVIDER: ${ARACHNE_STRANDS_MODEL_PROVIDER:-}
ARACHNE_STRANDS_MODEL_ID: ${ARACHNE_STRANDS_MODEL_ID:-}
ARACHNE_STRANDS_MODEL_REGION: ${ARACHNE_STRANDS_MODEL_REGION:-}
この構成で同じモデル設定を共有できますが、サービス境界の有無は呼び出し経路で確認します。
order-service 側の LLM 呼び出しは service-local(ArachneOrderIntentPlanner.java)
order-service は order-intake-agent の system prompt と structured output 型を自サービス内で定義し、独立して LLM を呼び出します。
// ArachneOrderIntentPlanner.java(抜粋)
AgentResult result = observationSupport.observe(
"order-service",
AGENT_NAME,
sessionId,
prompt.render(),
() -> agentFactory.builder()
.systemPrompt(systemPrompt(locale))
.build()
.run(prompt.render(), NormalizedOrderIntent.class));
この呼び出しは NormalizedOrderIntent.class の範囲で完結し、menu-service の型や tool 定義に依存しません。
サービス間は HTTP ペイロードで接続(RegistryBackedMenuGateway.java)
order-service から menu-service への接続は、POST /internal/menu/suggest の REST 呼び出しです。
// RegistryBackedMenuGateway.java(抜粋)
Objects.requireNonNull(restClient.post()
.uri(endpointResolver.resolveUrl(menuCapabilityQuery, "/internal/menu/suggest"))
.header(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken)
.contentType(MediaType.APPLICATION_JSON)
.body(request)
.retrieve()
.body(MenuSuggestionResponse.class));
ここでの境界は LLM ではなく HTTP 契約です。order-service は MenuSuggestionRequest を送り、MenuSuggestionResponse を受け取ります。
menu-service 側の LLM 呼び出しも service-local(MenuApplicationService.java)
menu-service は別の system prompt と別の tool セットで、独立して LLM を呼び出します。
// MenuApplicationService.java(抜粋)
AgentResult result = agentObservationSupport.observe(
"menu-service", "menu-agent", request.sessionId(), userPrompt.render(), agentState,
() -> agentFactory.builder()
.sessionId(request.sessionId())
.state(agentState)
.systemPrompt(buildSuggestionSystemPrompt())
.tools(catalogLookupTool, calculateTotalTool)
.build()
.run(userPrompt.render(), MenuSelectionDecision.class));
出力型は MenuSelectionDecision.class で、order-service の NormalizedOrderIntent とは別の契約です。
観察された振る舞い
- order-service の責務は「注文意図の正規化」で、menu-service の責務は「catalog grounding と候補選定」に分離されていた。
- 両サービスは同じモデル設定を共有できるが、system prompt・tool・structured output 型はサービスごとに独立して定義されていた。
- サービス間で渡るのは
MenuSuggestionRequestの HTTP ペイロードのみで、LLM の内部状態を共有する経路はコード上に現れなかった。
- サービス間で渡るのは
- obs-01 の trace 記録でも
order-intake-agentとmenu-agentは別サービスの別イベントとして記録されていた。
確認できる場所
food-delivery-demo/compose.yml(モデル設定環境変数の共有)order-service/.../ArachneOrderIntentPlanner.java(order-service 内の LLM 呼び出し)order-service/.../RegistryBackedMenuGateway.java(service 間の HTTP 契約)menu-service/.../MenuApplicationService.java(menu-service 内の LLM 呼び出し)site/src/content/observations/01-natural-language-front-door.mdx(両サービスの trace 例)