Skip to content

Commit 91426ac

Browse files
authored
docs(js): Adds doc for context. (#1843)
1 parent 95b0d0e commit 91426ac

File tree

1 file changed

+172
-0
lines changed

1 file changed

+172
-0
lines changed

docs/context.md

+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
# Passing information through context
2+
3+
When working with LLMs, there are often different categories of information
4+
being handled simultaneously:
5+
6+
- **Input:** Information that is directly relevant to guide the LLM's response
7+
for a particular call such as the text that needs to be summarized.
8+
- **Generation Context:** Information that is relevant to the LLM but isn't
9+
specific to the call, such as the current time or a user's name.
10+
- **Execution Context:** Information that is important to the code surrounding
11+
the LLM call but not to the LLM itself, e.g. a user's current auth token.
12+
13+
Genkit provides a consistent `context` object that can propagate generation and
14+
execution context throughout the process. This context is made available to all
15+
actions including [flows](flows), [tools](tool-calling), and
16+
[prompts](dotprompt).
17+
18+
Context is automatically propagated to all actions called within the scope of
19+
execution - context passed to a flow will be made available to prompts executed
20+
within the flow. Context passed to the `generate()` method will be available to
21+
tools called within the generation loop.
22+
23+
## Why is context important?
24+
25+
As a best practice, you should provide the minimum amount of information to the
26+
LLM that it needs to complete a task. This is important for multiple reasons:
27+
28+
- The less extraneous information the LLM has, the more likely it is to perform
29+
well at its task.
30+
- If an LLM needs to pass around information like user or account ids to tools,
31+
it can potentially be tricked into leaking information.
32+
33+
Context gives you a side channel of information that can be used by any of your
34+
code but doesn't necessarily have to be sent to the LLM. As an example, it can
35+
allow you to restrict tool queries to the current user's available scope.
36+
37+
## Context structure
38+
39+
Context must be an object, but its properties are yours to decide. In some
40+
situations Genkit will automatically populate context. For example, when using
41+
[persistent sessions](chat) the `state` property is automatically added to
42+
context.
43+
44+
One of the most common uses of context is to store information about the current
45+
user. We recommend adding auth context in the following format:
46+
47+
```js
48+
{
49+
auth: {
50+
uid: "...", // the user's unique identifier
51+
token: {...}, // the decoded claims of a user's id token
52+
rawToken: "...", // the user's raw encoded id token
53+
// ...any other fields
54+
}
55+
}
56+
```
57+
58+
The context object can store any information that you might need to know somewhere
59+
else in the flow of execution.
60+
61+
## Use context in an action
62+
63+
To use context within an action, you can access the provided context helper
64+
that is automatically supplied to your function definition:
65+
66+
* {Flow}
67+
68+
```ts
69+
const summarizeHistory = ai.defineFlow({
70+
name: 'summarizeMessages',
71+
inputSchema: z.object({friendUid: z.string()}),
72+
outputSchema: z.string();
73+
}, async ({friendUid}, {context}) => {
74+
if (!context.auth?.uid) throw new Error("Must supply auth context.");
75+
const messages = await listMessagesBetween(friendUid, context.auth.uid);
76+
const {text} = await ai.generate({
77+
prompt:
78+
`Summarize the content of these messages: ${JSON.stringify(messages)}`,
79+
});
80+
return text;
81+
});
82+
```
83+
84+
* {Tool}
85+
86+
```ts
87+
const searchNotes = ai.defineTool({
88+
name: 'searchNotes',
89+
description: "search the current user's notes for info",
90+
inputSchema: z.object({query: z.string()}),
91+
outputSchmea: z.array(NoteSchema);
92+
}, async ({query}, {context}) => {
93+
if (!context.auth?.uid) throw new Error("Must be called by a signed-in user.");
94+
return searchUserNotes(context.auth.uid, query);
95+
});
96+
```
97+
* {Prompt file}
98+
99+
When using [Dotprompt templates](dotprompt), context is made available with the
100+
`@` variable prefix. For example, a context object of
101+
`{auth: {name: 'Michael'}}` could be accessed in the prompt template like so:
102+
103+
```none
104+
---
105+
input:
106+
schema:
107+
pirateStyle?: boolean
108+
---
109+
110+
{{#if pirateStyle}}
111+
Avast, {{@auth.name}}, how be ye today?
112+
{{else}}
113+
Hello, {{@auth.name}}, how are you today?
114+
{{/if}}
115+
```
116+
117+
## Provide context at runtime
118+
119+
To provide context to an action, you pass the context object as an option
120+
when calling the action.
121+
122+
* {Flows}
123+
124+
```ts
125+
const summarizeHistory = ai.defineFlow(/* ... */);
126+
127+
const summary = await summarizeHistory(friend.uid, {context: {auth: currentUser}});
128+
```
129+
130+
* {Generation}
131+
132+
```ts
133+
const {text} = await ai.generate({
134+
prompt: "Find references to ocelots in my notes.",
135+
// the context will propagate to tool calls
136+
tools: [searchNotes],
137+
context: {auth: currentUser},
138+
});
139+
```
140+
141+
* {Prompts}
142+
143+
```ts
144+
const helloPrompt = ai.prompt('sayHello');
145+
helloPrompt({pirateStyle: true}, {context: {auth: currentUser}});
146+
```
147+
148+
## Context propagation and overrides
149+
150+
By default, when you provide context it is automatically propagated to all
151+
actions called as a result of your original call. If your flow calls other
152+
flows, or your generation calls tools, the same context will be provided.
153+
154+
If you wish to override context within an action, you can pass a different
155+
context object to replace the existing one:
156+
157+
```ts
158+
const otherFlow = ai.defineFlow(/* ... */);
159+
160+
const myFlow = ai.defineFlow({
161+
// ...
162+
}, (input, {context}) => {
163+
// override the existing context completely
164+
otherFlow({/*...*/}, {context: {newContext: true}});
165+
// or selectively override
166+
otherFlow({/*...*/}, {context: {...context, updatedContext: true}});
167+
});
168+
```
169+
170+
When context is replaced it propagates the same way. In the above example,
171+
any actions that `otherFlow` called during its execution would inherit the
172+
overridden context.

0 commit comments

Comments
 (0)