컨텍스트를 통해 정보 전달

LLM으로 작업하는 개발자가 동시에 처리할 수 있는 정보 카테고리는 다음과 같습니다.

  • 입력: 특정 호출에 대한 LLM의 응답을 안내하는 데 직접적으로 관련된 정보입니다. 요약해야 하는 텍스트가 그 예입니다.
  • 생성 컨텍스트: LLM과 관련이 있지만 호출과 관련이 없는 정보입니다. 현재 시간 또는 사용자 이름이 여기에 해당합니다.
  • 실행 컨텍스트: LLM 호출을 둘러싼 코드에는 중요하지만 LLM 자체에는 중요하지 않은 정보입니다. 사용자의 현재 인증 토큰이 여기에 해당합니다.

Genkit은 프로세스 전반에서 생성 및 실행 컨텍스트를 전파할 수 있는 일관된 context 객체를 제공합니다. 이 컨텍스트는 흐름, 도구, 프롬프트를 비롯한 모든 작업에 제공됩니다.

컨텍스트는 실행 범위 내에서 호출된 모든 작업에 자동으로 전파됩니다. 흐름에 전달된 컨텍스트는 흐름 내에서 실행된 프롬프트에 사용할 수 있습니다. generate() 메서드에 전달된 컨텍스트는 생성 루프 내에서 호출되는 도구에서 사용할 수 있습니다.

맥락이 중요한 이유는 무엇인가요?

태스크를 완료하는 데 필요한 최소한의 정보를 LLM에 제공하는 것이 좋습니다. 이는 다음과 같은 여러 가지 이유로 중요합니다.

  • LLM에 불필요한 정보가 적을수록 작업을 잘 수행할 가능성이 높습니다.
  • LLM이 사용자 또는 계정 ID와 같은 정보를 도구에 전달해야 하는 경우 속아 정보를 유출할 수 있습니다.

컨텍스트는 모든 코드에서 사용할 수 있지만 LLM에 전송할 필요는 없는 정보의 부채널을 제공합니다. 예를 들어 도구 쿼리를 현재 사용자의 사용 가능한 범위로 제한할 수 있습니다.

컨텍스트 구조

컨텍스트는 객체여야 하지만 속성은 개발자가 결정합니다. 경우에 따라 Genkit에서 컨텍스트를 자동으로 채웁니다. 예를 들어 지속형 세션을 사용하면 state 속성이 컨텍스트에 자동으로 추가됩니다.

컨텍스트의 가장 일반적인 용도 중 하나는 현재 사용자에 관한 정보를 저장하는 것입니다. 다음 형식으로 인증 컨텍스트를 추가하는 것이 좋습니다.

{
  auth: {
    uid: "...", // the user's unique identifier
    token: {...}, // the decoded claims of a user's id token
    rawToken: "...", // the user's raw encoded id token
    // ...any other fields
  }
}

컨텍스트 객체는 실행 흐름의 다른 곳에서 알아야 할 정보를 저장할 수 있습니다.

작업에서 컨텍스트 사용

작업 내에서 컨텍스트를 사용하려면 함수 정의에 자동으로 제공되는 컨텍스트 도우미에 액세스하면 됩니다.

const summarizeHistory = ai.defineFlow({
  name: 'summarizeMessages',
  inputSchema: z.object({friendUid: z.string()}),
  outputSchema: z.string();
}, async ({friendUid}, {context}) => {
  if (!context.auth?.uid) throw new Error("Must supply auth context.");
  const messages = await listMessagesBetween(friendUid, context.auth.uid);
  const {text} = await ai.generate({
    prompt:
      `Summarize the content of these messages: ${JSON.stringify(messages)}`,
  });
  return text;
});
const searchNotes = ai.defineTool({
  name: 'searchNotes',
  description: "search the current user's notes for info",
  inputSchema: z.object({query: z.string()}),
  outputSchmea: z.array(NoteSchema);
}, async ({query}, {context}) => {
  if (!context.auth?.uid) throw new Error("Must be called by a signed-in user.");
  return searchUserNotes(context.auth.uid, query);
});

Dotprompt 템플릿을 사용하면 @ 변수 접두사로 컨텍스트를 사용할 수 있습니다. 예를 들어 {auth: {name: 'Michael'}}의 컨텍스트 객체는 프롬프트 템플릿에서 다음과 같이 액세스할 수 있습니다.

---
input:
  schema:
    pirateStyle?: boolean
---

{{#if pirateStyle}}
Avast, {{@auth.name}}, how be ye today?
{{else}}
Hello, {{@auth.name}}, how are you today?
{{/if}}

런타임에 컨텍스트 제공

작업에 컨텍스트를 제공하려면 작업을 호출할 때 컨텍스트 객체를 옵션으로 전달합니다.

const summarizeHistory = ai.defineFlow(/* ... */);

const summary = await summarizeHistory(friend.uid, {context: {auth: currentUser}});
const {text} = await ai.generate({
  prompt: "Find references to ocelots in my notes.",
  // the context will propagate to tool calls
  tools: [searchNotes],
  context: {auth: currentUser},
});
const helloPrompt = ai.prompt('sayHello');
helloPrompt({pirateStyle: true}, {context: {auth: currentUser}});

컨텍스트 전파 및 재정의

기본적으로 컨텍스트를 제공하면 원래 호출의 결과로 호출된 모든 작업에 자동으로 전파됩니다. 흐름이 다른 흐름을 호출하거나 생성이 도구를 호출하는 경우 동일한 컨텍스트가 제공됩니다.

작업 내에서 컨텍스트를 재정의하려면 다른 컨텍스트 객체를 전달하여 기존 컨텍스트를 대체하면 됩니다.

const otherFlow = ai.defineFlow(/* ... */);

const myFlow = ai.defineFlow({
  // ...
}, (input, {context}) => {
  // override the existing context completely
  otherFlow({/*...*/}, {context: {newContext: true}});
  // or selectively override
  otherFlow({/*...*/}, {context: {...context, updatedContext: true}});
}); 

컨텍스트가 대체되면 동일한 방식으로 전파됩니다. 이 예에서 otherFlow가 실행 중에 호출한 모든 작업은 재정의된 컨텍스트를 상속합니다.